I would like to make a DM script acquiring camera images continuously, like VIEW mode. In my plan, the continious camera acquisition is start when START button located at an UIframe dialog is pressed; and a modeless dialog is also shown simultaneously. The continuous acuisition is stopped when the OK button located at the dialog is pressed. For this kind of scripts, I think a background thread is required. However, I don't have enough knowledge about such a background running.
It will be appreciated if you share some wisdom. Thank you very much in advance.
Continuous camera acquisition has actually nothing to do with background-threading in scripting, but rather requires setting the hardware into a continuous readout mode.
This functionality is no supported by the official scripting API up to now.
However, there exits an extended, object-oriented scripting API which gives a more in-depth control over cameras. You will need to be versatile in the object-oriented coding style of DM-scripting to use it, and you will need to get in contact with Gatan to possibly get access to this script API, as it is not officially supported.
You may want to use the support-request form on the Gatan homepage for this. (button on bottom of page)
Picking up on the kachigusa's comment to my other answer....
If you want to run a slow camera acquistion pseudo-continously, that is by performing repeated single readouts on a separate thread, then you may want to use a structure like the following:
class CMyBackgroundAction
{
number isRunning
CMyBackgroundAction(object self) { isRunning = 0; } // Initialisation in constructor
// methods to access flag from outside the object
void StopRunning(object self) { isRunning = 0; }
number GetIsRunning(object self) { return isRunning; }
// The stuff that should run in the background until the flag is set
void RunUntilBreak(object self)
{
Result("\n\n StartRunning")
isRunning = 1
while (isRunning)
{
Result( "\n New line..." )
sleep(0.5)
Result( "....done" )
}
Result("\n\n FINISHED")
}
}
class CmyDLG : UIframe
{
object backGroundRunObj
void OnStartStop( object self )
{
if ( !backGroundRunObj.GetIsRunning() )
{
// Nothing running in the background yet.
backGroundRunObj.StartThread( "RunUntilBreak" )
self.LookUpElement("StartStopButton").DLGTitle("Stop")
}
else
{
// It exists, so it is running. Just set the break-flag
backgroundRunObj.StopRunning();
self.LookUpElement("StartStopButton").DLGTitle("Start")
}
}
TagGroup BuildDLG( object self )
{
TagGroup dlg, dlgitems
dlg = DLGCreateDialog("StartStop",dlgItems)
dlgItems.DLGAddElement( DLGCreatePushButton( "Start", "OnStartStop" ).DLGIdentifier("StartStopButton" ) )
return dlg
}
Object Init(object self)
{
backGroundRunObj = Alloc(CMyBackgroundAction)
self.super.Init( self.BuildDLG() )
return self
}
}
Alloc(CmyDLG).Init().Display("Test")
There are of course several other constructs with a dialog governing a separate thread. This is just an example.
If you are going to start/stop something which performs in very regular intervals, but requires the main thread - another option would be to register/deregister periodic tasks from a dialog. Here is an example:
class CMyBackgroundAction
{
// The stuff that should run periodically
void RunUntilBreak(object self)
{
Result("\n Doing action @" + GetTime(1) )
}
}
class CmyDLG : UIframe
{
object backGroundRunObj
number taskID
void OnStartStop( object self )
{
if ( 0 == taskID )
{
// Start by registering the task ( every 0.5 sec)
taskID = AddMainThreadPeriodicTask(backGroundRunObj,"RunUntilBreak",0.5)
Result("\n STARTED ")
self.LookUpElement("StartStopButton").DLGTitle("Stop")
}
else
{
// Stop by removing the task
RemoveMainThreadTask( taskID )
Result("\n STOPPED ")
taskID = 0
self.LookUpElement("StartStopButton").DLGTitle("Start")
}
}
TagGroup BuildDLG( object self )
{
TagGroup dlg, dlgitems
dlg = DLGCreateDialog("StartStop",dlgItems)
dlgItems.DLGAddElement( DLGCreatePushButton( "Start", "OnStartStop" ).DLGIdentifier("StartStopButton" ) )
return dlg
}
Object Init(object self)
{
backGroundRunObj = Alloc(CMyBackgroundAction)
taskID = 0
return self.super.Init( self.BuildDLG() )
}
}
Alloc(CmyDLG).Init().Display("Test")