Hi Michael,
In a slightly unrelated topic, how can one change an attribute value in a worker process from the main thread? I can see how workers are created, and how functions are called and returned between a worker and its parent, but what if I wanted to change an aspect of the worker after it has been created? Say a worker has some flag set to true when it was created by the tab, but at a later point id like to toggle that flag during idle. How can I communicate the UI change to the worker?
Methods (decorated with
@define_state(...)) of the BLACS tab can interact with a BLACS worker using the yield keyword. This can only be used to call a method of the BLACS worker, not directly update a variable in the worker directly. However, you can just write a method in the worker to update the variable. Note that
@define_state decorator ensures the BLACS tab method is executed by the BLACS tab statemachine at the appropriate time (and not necessarily immediately)
Using your suggested example, you would place a checkbox (that you can toggle) in the BLACS tab GUI, and connect the Qt clicked signal to your new BLACS tab method. This method should be decorated with @define_state(...), meaning clicks of the checkbox will queue up an event, not execute your method. There are 3 arguments to @define_state (one of which is optional). The first indicates what "modes" your method can run in. This will likely just be MODE_MANUAL (importable from blacs.tab_base_classes) as I suspect you don't want things to change on GUI click during buffered execution of shots or the transitions to/from that mode. The second argument is called queue_state_indefinitely, and indicates whether you would like the queued event (to execute your method) to stay in the queue even if it can't run yet (like for example if you were in buffered mode). True means it sticks around until it can run, False means it's deleted if it can't run. Typically you want True for this value, otherwise you get an inconsistent state between the actual Qt checkbox state and whatever it feeds into. The third argument is called delete_stale_states, and defaults to False (so is optional). In this case, you should set it to True - what it does is compress N sequential method events into only the last one. So if someone toggles the checkbox faster than the worker can process, it doesn't back up and execute each one, it throws the early ones away and takes the most up-to-date event.
So you want something like (in your BLACS tab):
@define_state(MODE_MANUAL, True, True)
def on_checkbox_clicked(self, checkbox_state):
# checkbox_state is provided by the Qt clicked signal
pass
I've left off the Qt signal connection in the tab initialisation code for brevity
Then you'll want to queue up some work. This can be done using:
return_data = yield(self.queue_work(self.primary_worker, 'worker_method_name', checkbox_state))
And then you'll want a worker method like:
class MyWorker(Worker)
...
def worker_method_name(self, checkbox_state):
# update worker attribute, program device, whatever
And that is pretty much it! Let me know if anything doesn't make sense.
Cheers,
Phil
Thank you very much, that did the trick and now I see how it's all saved.
In a slightly unrelated topic, how can one change an attribute value in a worker process from the main thread? I can see how workers are created, and how functions are called and returned between a worker and its parent, but what if I wanted to change an aspect of the worker after it has been created? Say a worker has some flag set to true when it was created by the tab, but at a later point id like to toggle that flag during idle. How can I communicate the UI change to the worker?
If I understand it right it looks like when a tab tells a worker to do something it calls put() with the allowed states, the function to call, and its arguments (triggered by a yield command). But I can't seem to figure out how to change an attribute of the worker itself.