LabVIEW

cancel
Showing results for 
Search instead for 
Did you mean: 

How to avoid built-up for "cursor move" events?

Solved!
Go to solution
I have a rather complicated program where several graphs need to be interactively updated according to cursors using "cursor move" events. The problem is that the recalculation is relatively slow and the behavior is less than satisfactory. Since the cursor position needs to be "tweaked" until the result is as desired, I cannot recalculate only at the "Cursor Release" event.
  • Lock front panel=enabled makes cursor movements tedious because the cursor movements is very
    jumpy and non-interactive. Not user friendly!
  • Lock front panel=disabled queues up way too many move events and once the cursor is released
    the graph continues to jump and recalculate for ages.

The attached demo (LabVIEW 8.20) shows one solution attempt that actually works pretty well: Skip the recalculation unless the cursor position from the event terminal is equal to the cursor position of the graph property node. This basically races through all unecessary intermediary recalculations on stale positions. However, the code can get complicated very quickly if there are multiple cursors.

In my opinion, cursor move events should not get queued up! The event buffer should hold only exactly one entry:
the most recent cursor position for each cursor. Can anyone think of a scenario where the extra cursor position trail is useful? The positions are pretty random anyway, right?
 
Does anyone have other (better!) ideas how to work around this problem? I definitely want to keep it simple and not throw lots of code at it.
 
The attached demo contains more details. It demonstrates the problem if "selective updates" is checked. If unchecked, it implements the above mentioned workaround.
Message 1 of 22
(10,931 Views)
Hi altenbach,

what about a queue of 1 element where the add to queue has a 0 ms timeout. My test works OK:


Edit:Flush queue is mandatory
Ton

Message Edited by TonP on 09-27-2006 07:38 AM

Free Code Capture Tool! Version 2.1.3 with comments, web-upload, back-save and snippets!
Nederlandse LabVIEW user groep www.lvug.nl
My LabVIEW Ideas

LabVIEW, programming like it should be!
Message 2 of 22
(10,916 Views)

Thanks Ton, interesting idea but needs some adjustment. 😉

The major flaw is that there is no guarantee that the very last cursor position causes a recalculation. Since queue elements are randomly thrown out. My example is designed that the curve must intercept the baseline (y=0) at the cursor position once the cursor is released. If I implement your code, the cursor often does not coincide with the location where the curve crosses zero after I release the cursor.

However, I think the following modification will solve this problem: Remove the "flush queue" after the "dequeue" and insert in in front of the "enqueue" operation instead. 😄

(My real program is much more complex and has about 4 graphs that all need to get updated as the cursors are moved and all the calculations take place in the main loop. I would prefer to keep all graph terminals in one loop.)

 

0 Kudos
Message 3 of 22
(10,908 Views)

HIi Christian,

The Event structure will return the Time of the event.

If you compare the time with the tick clock you can ignore any event that happened more than (?) 1 second ago.

I hope that helps,

Ben

Retired Senior Automation Systems Architect with Data Science Automation LabVIEW Champion Knight of NI and Prepper LinkedIn Profile YouTube Channel
Message 4 of 22
(10,890 Views)
Ow I missed this on:

What about the cursor release event? This only won't be fired when the mouse is still down....

But what about using the cursor grab event, and then periodicallyh poll the position of the cursor (and use Cursor release to stop polling)

Ton

Message Edited by TonP on 09-27-2006 05:18 PM

Message Edited by TonP on 09-27-2006 05:20 PM

Free Code Capture Tool! Version 2.1.3 with comments, web-upload, back-save and snippets!
Nederlandse LabVIEW user groep www.lvug.nl
My LabVIEW Ideas

LabVIEW, programming like it should be!
Message 5 of 22
(10,873 Views)
Ben,
 
The timing test will often throw out the very last cursor move, leaving the graph and plot misaligned after cursor release. I would have to add an explicit "cursor release" event to force a final calculation.


@TonP wrote:
But what about using the cursor grab event, and then periodically poll the position of the cursor (and use Cursor release to stop polling)
Ton,
 
Hehe, this is actually similar to the way I did things before the introduction of the "cursor move" and "cursor grab" events (pre 8.0). 🙂 Basically a state machine that (1) watches for "mouse down" events on all graphs, (2) places the selected graph ID in a shift register (3) sets the timeout to a finite number, polls the cursor position of the graph where the "mouse down" occurred, and recalculates whenever the cursor position has changed. (4) "mouse up" and "mouse leave" would then again disable the timeout polling.
 
I switched to the "mouse move" events to get away from all this! 😉
 
I can see that the "cursor grab" event would simplify things slightly. I'll play around a bit. Sitll, it involves much more code.
0 Kudos
Message 6 of 22
(10,858 Views)
This is a generic problem that I usually call "event throttling."  You run into it with the value change event on slider controls as well.  I usually solve it by using a shift register to keep track of the following information:
  1. Last time the event fired
  2. Minimum time between events
  3. "Needs Refresh" boolean flag
  4. Process identifier
  5. Optional value of the item changing (can also take this directly from the front panel when handling the event)
Note that this take place in an event-driven task handler.  When the event fires, the event time is compared to the last event time and the process is either handled or deferred.  The timeout case checks to determine if an event needs to be fired and does so.

I looked for some example code and found some code which demonstrates the idea using local variables.  I would strongly recommend you use a shift register instead, but this shows the idea.  This particular example uses a slider to set the end value or length of a waveform being read from disk.  The task is handled by a consumer loop not shown in the graphics.  There are several events being throttled - hence the arrays.






For an even better implementation, you can set the timeout to -1 when you don't need it and 20 (or whatever) when you do.


Message Edited by DFGray on 09-28-2006 07:53 AM

Download All
Message 7 of 22
(10,823 Views)
Solution
Accepted by altenbach
Thanks for the example.
 
The more I think about this, I strongly prefer my original method. 😄 It uses minimal code compare to the other solutions offered here. As a demo, I am attaching an implementation to a slide control.
 
Fo those without LabVIEW 8.20.
  1. All slide events have "lock front panel" disabled.
  2. TIme delay is 500ms, simulating some complex calculation.

As you can see, it works extremely well: 🙂

NO shift registers, extra loops, queues, tuning parameters (min times, etc.), etc.etc.

Just a deceptively simple "equal" followed by a case structure.

The demo shows a typical recording if I quicky move the slide up and down, then release it. You can see that the raw event structure takes more than 40 seconds to stabilize while my selective solution follows the slider position almost perfectly despite the 500ms stall in each update.

See for yourself! Can anyone think of a drawback of this method? Even if the slide terminal is not in the same loop, a comparison of a local variable with the newval should do the trick just fine.

Message Edited by altenbach on 09-28-2006 12:43 PM

Download All
Message 8 of 22
(10,801 Views)


@altenbach wrote:

See for yourself! Can anyone think of a drawback of this method? Even if the slide terminal is not in the same loop, a comparison of a local variable with the newval should do the trick just fine.


I have done this in the past, only in my case the event case registered value change events for several controls. Looking at the code, I see I used the CtlRef terminal to get the Value property of the control, but that I added a small wait before getting it. I don't know if that was a precaution or if I did it because the values didn't always update immediately (that specific bit of the code was written in a hurry, because it was only discovered that this caused some annoying UI delays when we were at the actual site, so I guess I never got around to putting in a comment about it).

___________________
Try to take over the world!
Message 9 of 22
(10,764 Views)
Very nice.  I will have to remember that one...
0 Kudos
Message 10 of 22
(10,755 Views)