From Friday, April 19th (11:00 PM CDT) through Saturday, April 20th (2:00 PM CDT), 2024, ni.com will undergo system upgrades that may result in temporary service interruption.

We appreciate your patience as we improve our online experience.

LabVIEW

cancel
Showing results for 
Search instead for 
Did you mean: 

Moving Objects with Mouse using Dynamic Event Registration


LabBEAN wrote:

 

Were you thinking of unregistering while handling the event that you caught and then re-registering?

No, and I'm guessing this doesn't work as you expect. One problem that immediately comes to mind can be illustrated like this: Add a 2 second wait before unregistering. Presumably all the events that happened before the unregister are still processed, thus missing the point.

 


Allusion to the Brain, LabVIEW Everywhere (Touch Panel, PDA, RT, FPGA, ADI Blackfin, ...), or both?

 


I used to have a habit or changing my avatars regularly and using some relevant sentence as a signature. At some point I got stuck with the Brain.


___________________
Try to take over the world!
0 Kudos
Message 11 of 32
(2,608 Views)

tst wrote:

No, and I'm guessing this doesn't work as you expect. One problem that immediately comes to mind can be illustrated like this: Add a 2 second wait

before unregistering. Presumably all the events that happened before the unregister are still processed, thus missing the point.


 

 

Execution order:

 

Dynamic Event Registration for Value Change event on sliders

Inside the Value Change event case, unregister for the Value Change events (no other code inside that event case)

Go read sliders and then enqueue hardware loop to write new DAQmx task values

After writing is complete enqueue back to the GUI loop to re-register the value change event

 

I first started using this method about 3 years ago, and I don't *think* I've seen any issues with it...


Certified LabVIEW Architect
TestScript: Free Python/LabVIEW Connector

One global to rule them all,
One double-click to find them,
One interface to bring them all
and in the panel bind them.
0 Kudos
Message 12 of 32
(2,599 Views)
OK, a quick test seems to show that registering a null reference for an event flushes all those events from the queue, which is why this works. I haven't tried anything else, such as checking whether this clears other events from the queue (although hopefully it doesn't) or seeing what happens if you register another control for the same event.

___________________
Try to take over the world!
0 Kudos
Message 13 of 32
(2,577 Views)

 


tst wrote:

 

I haven't tried anything else, such as checking whether this clears other events from the queue (although hopefully it doesn't) or seeing what happens if you register another control for the same event.


 
Not sure what you mean by "another control" and "same event", but here's the basic architecture.
 
The VI Snippet attached after the following image dropped the local variable (Event Reg Ref) that was feeding the Dynamic Event Terminals and recoded it with a reference and property node.
 
 

 Dyn Event Reg - Unreg for Sliders.png


Certified LabVIEW Architect
TestScript: Free Python/LabVIEW Connector

One global to rule them all,
One double-click to find them,
One interface to bring them all
and in the panel bind them.
0 Kudos
Message 14 of 32
(2,558 Views)

JackDunaway wrote: 

 

Finally, when a "Mouse Up" has been detected, that signals we no longer need to respond to the Mouse Move events, so wiring another Null ref (of the same type) into the Register for Events node cancels that previous registration's event queue, trashing any events that have not yet been handled. (That's an anecdotal observation, can someone confirm?) 



tst wrote: 

 

OK, a quick test seems to show that registering a null reference for an event flushes all those events from the queue, which is why this works.


 
Yep, one of the only functions we have available to the underlying event queue is "Flush Queue". It would be nice to have some more control over that queue - still waiting to hear back from AQ here (maybe his superiors have put a muzzle on him...)
0 Kudos
Message 15 of 32
(2,557 Views)

LabBEAN wrote:

 Dyn Event Reg - Unreg for Sliders.png


1. I understand Producer Loops and Consumer Loops, but what's a Producer/Consumer loop? That being said, why the GUI Producer/Consumer Loop? It seems like an unnecessary middleman between GUI Producer and Hardware Consumer.

2. How do you force the loop iteration of the GUI Producer? With a "Ready" or "Finished" variable and a "Val (Sgnl)" event?

 

I would need to see this architecture in situ to agree with the 3 loops vs two, and the local with the necessity of the forced iteration. There's really no need to pass the dynamic events ref anywhere outside of the GUI Producer loop - re-registration of the Slider: Val Change event could happen within the "Finished" forced iteration.

 

Also, using the "Unregister for Events" seems excessive - I would prefer the cleaner syntax of wiring in a null ref to the "Register for Events" terminal - it is self-documenting by saying "I'm still holding on to this event registration ref, just nulling it out for a while when I don't want to listen". The "Unregister for Events" is more of a cue for "see-ya, shuttin' down".

Message Edited by JackDunaway on 04-23-2010 12:42 PM
0 Kudos
Message 16 of 32
(2,535 Views)

A lot of this is probably personal preference, but after 8 years now, this is the architecture I've settled into.

 

GUI Producer = Event Handler

Pushing the event structure into it's own loop allows it to self throttle.  The loop waits until an event occurs (the timeout case never executes).  UI activity, like pressing a Boolean with "latch until released" mechanical behavior, is handled instantly (no need to finish a state and then enqueue a state to check the Event Structure).  This is personal preference, but I also prefer to debug loops that aren't constantly executing "Do Nothing" cases like Timeout, Default, etc.

 

 


JackDunaway wrote:

1. I understand Producer Loops and Consumer Loops, but what's a Producer/Consumer loop?


 

 

GUI Producer/Consumer » Dequeues states from itself and other loops and enqueues states to itself and other loops

It "consumes", for example, from the Hardware loop and might display live data (e.g. sensor values) to the user, or a multitude of other tasks.  It also "produces" to the Hardware, Timer, Data, etc. loops when parallel processing is necessary (e.g. File I/O, graphing, DAQ).  This is the "main" loop that kicks everybody off and shuts them down.

 

 


JackDunaway wrote:

...why the GUI Producer/Consumer Loop?  It seems like an unnecessary middleman between GUI Producer and Hardware Consumer.


 

 

I don't like having code in the Event Structure.  Sometimes the GUI Producer/Consumer is acting like a "middle-man", but other times there are a variety of states that need to execute in various loops before enqueing down to the Hardware loop.  For the sake of "sameness" and code readability, internally, we follow the guideline "keep code out of the event structure".  That keeps developers from getting tempted to do too much in there.  In fact, there isn't even a shift register on the GUI Producer for that very reason.  It needs to be very responsive and not get bogged down processing, making decisions, handling errors, etc.  This makes the code very easy to follow.  Because the loop is NOT freewheeling, it's easy to debug as well.  We only dequeue a state when we need to run that state (no "Do Nothing" states necessary here either).

 

 


JackDunaway wrote:

2. How do you force the loop iteration of the GUI Producer? With a "Ready" or "Finished" variable and a "Val (Sgnl)" event?


 

User event, Val(Sgnl), etc.

 

 

 


JackDunaway wrote:

 

There's really no need to pass the dynamic events ref anywhere outside of the GUI Producer loop - re-registration of the Slider: Val Change event could happen within the "Finished" forced iteration.


 

The local is necessary because of the architecture that I've just described.

 

I guess I've just thought of these as two independent functions:  unregister and iterate surrounding while loop.  I also use "iterate" to shut the loop down when closing for a reason other than a user action (e.g. panel close).  I suppose doing an extra "unregister" wouldn't hurt anything in that case.  Currently only the GUI Producer/Consumer tells the GUI Producer to iterate, so when the Hardware Producer/Consumer finishes the DAQmx generation (for example), it has to tell the GUI Producer/Consumer.  Again, this keeps the code structured -- only certain areas of the code have access to other areas.  So, I do the unregistering in the "Unregister for Events" since I'm passing through that state anyhow and that's what seemed logical to me at the time.  "Unregister" should happen immediately, so it's in the loop.  The other is less critical since the ES won't get it's new event subscription until the loop iterates.

 

Aside:  Maybe you're picturing actual "loops" on one huge diagram like my mock-up image...  The other loops are in subVIs or kicked off by VI Server.

 

 

 


JackDunaway wrote:

 

using the "Unregister for Events" seems excessive - I would prefer the cleaner syntax of wiring in a null ref to the "Register for Events" terminal



If you had multiple types of dynamic events being handled by the same event structure, then you would need to do as you write.  Just make sure to leave unwired the types of events you want to keep registered.

 

 

 


Certified LabVIEW Architect
TestScript: Free Python/LabVIEW Connector

One global to rule them all,
One double-click to find them,
One interface to bring them all
and in the panel bind them.
0 Kudos
Message 17 of 32
(2,524 Views)
Anthony Lukindo posted something similar here.  There's one small flaw that I comment about at the bottom of the article.

Certified LabVIEW Architect
TestScript: Free Python/LabVIEW Connector

One global to rule them all,
One double-click to find them,
One interface to bring them all
and in the panel bind them.
0 Kudos
Message 18 of 32
(2,522 Views)

LabBEAN wrote:

This is personal preference, but I also prefer to debug loops that aren't constantly executing "Do Nothing" cases like Timeout, Default, etc...


 

Agreed. I don't like freewheeling loops unless there's some specific code you want executing in the timeout case. Set -1 for event timeout and delete the Timeout case.

 

 


LabBEAN wrote:

I don't like having code in the Event Structure....


 

OK, here's really our only fundamental difference. I prefer having rich event structures that "do a lot". If I can fit all the synchronous actions into the event structure, then I do it. Notable exceptions that come to mind are database operations, kicking off modals for user input/notification, and networking operations - those are deferred to an asynchronous consumer. As a general rule, if the task can be completed within 50-100msec, I keep it in the event structure. Keeping a "snappy" UI means something that will respond within 100-200msec - it doesn't need to enqueue actions within 1microsec of a button press.

 


LabBEAN wrote:

Maybe you're picturing actual "loops" on one huge diagram like my mock-up image...  The other loops are in subVIs or kicked off by VI Server.....


 

 

Actually, no, I did not see a big diagram. I also find it more elegant to sometimes have a separate consumer process, especially when there are multiple producers. But with that being said, how do you pass around the dynamic events ref (if not by local)?

Message 19 of 32
(2,475 Views)

LabBEAN wrote:
Anthony Lukindo posted something similar here.  There's one small flaw that I comment about at the bottom of the article.

There's also another flaw... dropping a typedef'd constant on the BD and modifying it's value. If the structure of the typedef is ever changed, the values of all BD constants are not guaranteed to survive. And there's one more flaw... it's going to be difficult to trace the source of producer/consumer actions if the two loops are in separate VI's (not to mention how the ref will be passed around, who creates/destroys the ref, etc...)

 

***EDIT: Don't get me wrong, Anthony's level of detail is amazing. I'm nitpicking here.*** 

 

This method handles both problems by wrapping the queue ref, making it easy to find all operations that happen on the queue (just "Find All Callers" in project, or "Find All Instances" if your top level plus dynamic calls are open) The four actions are Create, Send, GetRef, and Destroy... your imagination can fill in the other case structures.  (does anyone else do something similar?)

 

MessageCommandWrapper.png

Message Edited by JackDunaway on 04-28-2010 12:49 PM
Message 20 of 32
(2,472 Views)