I would like a create a box with the field being update by another function (a loop in my example). Each time value changes, the display should change.
My first attempt create a box which displays only the last value.
Class MyTestDialog: UIFrame
{
TagGroup CreateMyDialog(Object self)
{
TagGroup DialogTG = DLGCreateDialog("useless text")
TagGroup Fields,FieldItems
Fields = DLGCreateBox("Current",FieldItems)
FieldItems.DLGAddElement(DLGCreateRealField(42,15,3).DLGIdentifier("#RField"))
DialogTG.DLGAddElement(Fields.DLGTableLayOut(3,1,0))
Return DialogTG
}
Void Doit(Object self,number count)
{
for (count=0; count<5; count++)
{
self.LookUpElement("#RField").DLGValue(sum(getfrontimage())*count)
self.Display("Text at top of box window")
sleep(3)
}
}
Object Init(Object self) return self.super.Init(self.CreateMyDialog())
}
Object MyBeamCurrentDisplay = Alloc(MyTestDialog).Init()
MyBeamCurrentDisplay.Display("Text at top of box window")
sleep(3)
MyBeamCurrentDisplay.Doit(5)
Your script actually works (except you don't want to re-display the dialog each time.), but because both the DM-script itself, as well as UI updating calls are handled on DM's main thread, you don't see an updated.
The dialog gets updated 5times, but the display of the dialog only gets updated once your script has finished, giving the main-thread CPU cycles to handle the UI update.
If you put your script on a background-thread, you will see it works:
// $BACKGROUND$
Class MyTestDialog: UIFrame
{
TagGroup CreateMyDialog(Object self)
{
TagGroup DialogTG = DLGCreateDialog("useless text")
TagGroup Fields,FieldItems
Fields = DLGCreateBox("Current",FieldItems)
FieldItems.DLGAddElement(DLGCreateRealField(42,15,3).DLGIdentifier("#RField"))
DialogTG.DLGAddElement(Fields.DLGTableLayOut(3,1,0))
Return DialogTG
}
Void Doit(Object self,number count)
{
for (count=0; count<5; count++)
{
self.LookUpElement("#RField").DLGValue(sum(getfrontimage())*count)
// self.Display("Text at top of box window")
sleep(0.1)
}
}
Object Init(Object self) return self.super.Init(self.CreateMyDialog())
}
Object MyBeamCurrentDisplay = Alloc(MyTestDialog).Init()
MyBeamCurrentDisplay.Display("Text at top of box window")
sleep(0.2)
MyBeamCurrentDisplay.Doit(20)
(The first line of the code has to be exactly // $BACKGROUND
)
An alternative way is to keep the script on the main thread, but add doEvents()
before your sleep(0.1)
to give some CPU cycles to the main application finishing queued task like updating UI's.
I also played a bit with updates and different threads and thought you might find the following example useful:
number TRUE = 1
number FALSE = 0
Class MyTestDialog: UIFrame
{
object messageQueue
object stoppedSignal
number updateTimeSec
void OnUpdateStateChanged(object self, taggroup checkboxTG )
{
if ( TRUE == checkboxTG.DLGGetValue() )
self.StartThread( "RegularFrontImageUpdate" )
else
messageQueue.PostMessage( Alloc(object) ) // Single message: Stop, so any object will do
}
number AboutToCloseDocument( object self, number verify )
{
result("\nAbout to close")
messageQueue.PostMessage( Alloc(object) ) // Single message: Stop, so any object will do
stoppedSignal.WaitOnSignal( infinity(), NULL ) // Ensure we don't kill the UI object while the update thread is still accessing it
return FALSE
}
TagGroup CreateMyDialog(Object self)
{
TagGroup DialogTG = DLGCreateDialog("useless text")
TagGroup Fields,FieldItems
Fields = DLGCreateBox("Current Front Image Sum",FieldItems)
FieldItems.DLGAddElement(DLGCreateStringField("No front image",30).DLGIdentifier("#StrField").DLGEnabled(FALSE))
FieldItems.DLGAddElement(DLGCreateRealField(0,15,3).DLGIdentifier("#RField").DLGEnabled(FALSE))
FieldItems.DLGAddElement(DLGCreateCheckbox("Update", TRUE, "OnUpdateStateChanged").DLGIdentifier("#ToggleCheck"))
DialogTG.DLGAddElement(Fields.DLGTableLayOut(3,1,0))
Return DialogTG
}
void RegularFrontImageUpdate(Object self)
{
stoppedSignal.ResetSignal()
self.SetElementIsEnabled("#RField",TRUE)
self.SetElementIsEnabled("#StrField",TRUE)
result("\nEnabling auto-update")
while(TRUE)
{
object message = messageQueue.WaitOnMessage( updateTimeSec, null )
if ( message.ScriptObjectIsValid() )
{
// Handle message. We just use 'empty' objects in this example
// as we only have a "single" message: Stop updating now!
self.LookUpElement("#ToggleCheck").DLGValue( 0 )
self.LookUpElement("#RField").DLGValue( 0 )
self.SetElementIsEnabled("#RField",FALSE)
self.SetElementIsEnabled("#StrField",FALSE)
result("\nDisabling auto-update")
break;
}
else
{
// Timeout of waiting time. Just update
image front := FindFrontImage()
if ( front.ImageIsValid() )
{
self.LookUpElement("#RField").DLGValue( sum(front) )
self.LookUpElement("#StrField").DLGValue( front.GetName() )
}
else
self.LookUpElement("#ToggleCheck").DLGValue( 0 )
}
}
stoppedSignal.SetSignal()
}
object Launch(object self)
{
updateTimeSec = 0.1
messageQueue = NewMessageQueue()
stoppedSignal = NewSignal( false )
self.Init(self.CreateMyDialog()).Display("Title")
self.StartThread( "RegularFrontImageUpdate" )
return self
}
}
Alloc(MyTestDialog).Launch()