Scripting Resources for DigitalMicrograph™

banner

Dave Mitchell's DigitalMicrograph™ Scripting Website

Home | Scripts | Examples | Functions | Recent Updates | Tutorials | Resources | Publications | Consulting | Projects | Contact & Bio |PyJEM| Search

 

Example:Using Two Listeners to do Live Processing
Function
An example script which uses two listeners to monitor a live image and the live FFT which it creates.
Version
20130803, v1.0
Author
D. R. G. Mitchell
Acknowledgements
Bernhard Schaffer and Vincent Hou did all the hard work of working out how to use this function.
Comments
An event listener is attached to the front-most live image. This listens for changes in that image. Every time it is updated the change method of the event listener is invoked. In this case it creates a live FFT. A key listener attached to the FFT is used to detect when the FFT is closed. This detaches the event listener from the live image and so stops the live FFT image from being recreated.

 

System Requirements
Should be compatible with all recent versions of DigitalMicrograph.
Known Issues
-
Supported
Yes
Included Files
Main script file.
Source Code

// This example script will carry out live FFT processing.

// It requires a live image refreshing on the screen. Alternatively it can be tested

// with a static image. Once this script has been run and the listeners applied,

// simply change the values in the static image with a one line script or use the

// Simple Math function.

 

// This script uses two listeners to monitor the live image and the resulting FFT.

// An event listener is attached to the front-most live image.

// This listens for changes in that image. If it is a live image, then every time it is updated

// the change method of the event listener will be invoked. In this case it creates

// a live FFT.

 

// The problem is that closing the live FFT does not close it permanently, since at the next

// update of the live image, the FFT will be recreated. So a second listener must be used. This is

// attached to the FFT image. When the FFT image is closed, the event listener on the live image

// is deactivated by the listener on the FFT image, and this stops the whole process.

 

// Acknowledgements: This is based on scripts by Bernhard Schaffer and Vincent Hou. The idea of attaching a key

// listener to an image to know when it has been closed is Bernhard's.

 

// D.R.G. Mitchell, adminnospam@dmscripting.com (remove the nospam to make this work)

// version:20130803, v1.0, www.dmscripting.com

 

 

// Global variable

 

image fftimg // the FFT of the front image

number eventtoken // The id of the event listener

 

 

// This is the event listener which is attached to the front-most live image

 

Class MyEventListener

{

// Function which responds when the data in img is changed.

// The event flag has a value of 4

void DataChanged(object self, number event_flag, image img)

{

// The sum value of the live image is calculated and placed in the results window

// simply to prove that it is picking up the changes in the live image

number sumval=sum(img)

result("\n\nLive image changed: sum="+sumval)

 

// A FFT is created and displayed. Using a global fftimg image variable ensures that the

// image is not created in multiple copies

fftimg=realfft(img)

showimage(fftimg)

string imgname=getname(img)

setname(fftimg, "Live FFT of "+imgname)

// The event listener returns a response which depends on what has been defined

// within the event map - basically what change is detected. The code below is here simply

// to demonstrate how to extract that information

string event_desc

Object img_event_mask = ImageGetEventMap()

img_event_mask.DeconstructEventFlags( event_flag, event_desc )

result("\nEvent : "+event_desc)

}

 

 

// This is the constructor - does nothing except output an update in the results window

 

MyEventListener( object self)

{

result("\n\nEvent Listener Constructor called.")

result("\nEvent Listener Added to Live Image")

}

// This destructor is invoked when the live image is closed - it does nothing.

// If the image to which the listener object is attached is closed, the object

// is destructed by default. The real work is done in the Destructor of the Key Listener

// If the FFT image is closed, the key listener removes the event listener from the live image.

// This event listener destructor is invoked by that action - but all it does is send a

// comment to the results window.

~MyEventListener(object self)

{

result("\n\nEvent Listener Destructor called.")

}

}

 

 

// This is the faux key listener which is added to the image display of the FFT image

// Key Listeners are used to make the image display respond to key presses. However, here

// its only used to detect when the imagedisplay is closed, as this causes the key listener

// to go out of scope and its destructor is called. The key listener's destructor is then used to remove

// the event listener from the live image.

 

Class FauxKeyListener

{

Number KeyToken // The id of the key listener

image eventimg // The live image to which the event handler has been attached

 

// This passes in to this Class the id of the key listener, which is created in the

// main program below

Void Init(Object self,Number keyListenerToken)

{

KeyToken=KeyListenerToken

}

// This function responds when a key is pressed. In this case key strokes

// are not sought. However, for demonstration purposes the relevant code

// is left in. If the 'esc' key is pressed, a response appears in the results window

// When using key handlers to simply check for the image being closed, the keyhandler()

// function need only contain a single line which says return 0

// The function must return a value - so zero seems like a good choice.

Number KeyHandler(Object self, ImageDisplay disp, Object keydescriptor)

{

// &&&&

// If key listening is being used solely to detect when an image is closed

// then all the code between the &&&& can be removed since understanding

// which key has been pressed is irrelevant.

If ( keydescriptor.MatchesKeyDescriptor("esc"))

{

Result("\nEscape pressed")

}

else

{

Result("\nYou pressed a key, but it was not 'Escape'.")

}

// &&&&

return 0

}

// This function passes in the live image to which the event handler is attached

// so that it is available to the destructor function to deactivate the event handler

void initialise(object self, image front)

{

eventimg:=front

}

// The constructor for the key Listener object. This does nothing except report

// the the results window

FauxKeyListener(object self)

{

result("\n\nKey Listener Constructor called.")

result("\nKey Listener has been added to FFT image")

}

// The destructor for the key Listener object. This function is the really

// useful part. When the FFT image is closed, its image display goes out of scope.

// The key listener therefore also goes out of scope and the destructor is called.

// The destructor is used to remove the event listener from the original live image.

// This ensures that closing the live FFT image, will actually stop it being recreated

// next time the Live image gets updated

~FauxKeyListener(object self)

{

result("\n\nFFT image closed - Key Listener Destructor called.")

result("\nKey Listener Destructor removing Event Listener from live image")

eventimg.imageRemoveEventListener(eventtoken)

}

}

 

 

// Main program wrapped in a function - this helps ensure that there are no memory leaks

 

Void main()

{

// Check that at least one image is displayed

number nodocs=countdocumentwindowsoftype(5)

if(nodocs<1)

{

showalert("Ensure a live image is displayed front-most.",2)

return

}

// Source the front-most image and check that it is not type 3 or 13 (complex 8 and 16)

// in case an FFT is front-most

image front := GetFrontImage()

front.setname("Live Image")

number imagetype=front.imagegetdatatype()

if(imagetype==3 || imagetype==13) // FFTs are complex - type = 3 or 13

{

showalert("This will not work on FFTs, ensure a real image is front-most.",2)

return

}

// Create the event listener object and add it to the front-most (live) image

// This listener will respond when that image is changed. The "data_value_changed:DataChanged"

// creates a mapping in the event map. data_value_changed is the event which is detected when the

// live image is changed. DataChanged is the method within the MyEventListener class

// which actually responds to the change.

object EventListener=alloc(MyEventListener)

string eventmap="data_value_changed:DataChanged"

EventToken = front.ImageAddEventListener(EventListener, eventmap)

 

 

// Invoke a (null) change in the image this forces a change which the event listener picks up.

// It then creates the FFT. Source the fftimage and then its image display

 

front=front-0

fftimg:=getfrontimage()

imagedisplay fftdisp=fftimg.imagegetimagedisplay(0)

 

 

// Create the key listener object.

Object keyListener = Alloc( FauxKeyListener )

// Initialise the object by passing in the front-most live image to which the

// event handler has been attached previously. The key listener needs access to this image

// since when the FFT image is closed, it will deactivate the event listener.

KeyListener.initialise(front)

// Add the key listener to the FFT image display. "KeyHandler" is the

// class method which responds to any key presses. In this case some

// example code is provided, such that pressing a key outputs some text

// to the results window. However, here the main purpose of the key handler is

// simply to respond when the FFT image is closed, by removing the event

// listener from the live image

Number KeyToken = fftdisp.ImageDisplayAddKeyHandler( keyListener, "KeyHandler" )

}

 

 

// Main program

 

main()