LabWindows/CVI

cancel
Showing results for 
Search instead for 
Did you mean: 

SetCtrlAttribute called from within a callback

So if I set a control attribute, say, ATTR_DIMMED, for control2 from within a callback function for control1, when will the second control get dimmed? 

 

Will control2 dim before the control1 callback returns? 

 

Will control2 dim if I call ProcessDrawEvents from within the control1 callback?

 

If I call ProcessDrawEvents from within the control1 callback, can other pending callbacks get invoked prior to the return from ProcessDrawEvents?

 

How about the same scenario but I call ProcessSystemEvents from within the control1 callback?

 

If I don't explicitly call ProcessSystemEvents or ProcessDrawEvents from within the control1 callback, is there any way another control callback can get invoked prior to exiting the control1 callback?

 

If I am waiting for a mutex from within the control1 callback (WaitForSingleObject), can another callback get invoked? 

 

Does dimming a control with a queued event discard the queued events?  If not, is there any way to flush queued events on a control that I've just dimmed?

 

Thanks.  

 

 

0 Kudos
Message 1 of 10
(4,487 Views)

Will control2 dim before the control1 callback returns? 

Yes, but it won't look dimmed

 

Will control2 dim if I call ProcessDrawEvents from within the control1 callback?

Then it will look dimmed after you call ProcessDrawEvents

 

If I call ProcessDrawEvents from within the control1 callback, can other pending callbacks get invoked prior to the return from ProcessDrawEvents?

ProcessDrawEvents does not invoke callbacks. All it does is update the display to reflect programmatic UI changes that you made since the last time events were processed.

 

How about the same scenario but I call ProcessSystemEvents from within the control1 callback?

If you call ProcessSystemEvents, pending callbacks can be invoked from within ProcessSystemEvents. These can include mouse click events on the control that you dimmed, if the mouse click happened before the start of the callback.


 

If I don't explicitly call ProcessSystemEvents or ProcessDrawEvents from within the control1 callback, is there any way another control callback can get invoked prior to exiting the control1 callback?

In a single-threaded situation, events can only be invoked if you call ProcessSystemEvents, GetUserEvent, RunUserInterface or DelayWithEventProcessing. There are also some less common situations involving functions such as CmtWaitForThreadPoolFunctionCompletion, or asynchronous driver events (for example, using the NI-DAQmx library).


 

If I am waiting for a mutex from within the control1 callback (WaitForSingleObject), can another callback get invoked?

No. Other threads, however, can invoke callbacks for panels created by those threads.

 

Does dimming a control with a queued event discard the queued events?  If not, is there any way to flush queued events on a control that I've just dimmed?

No, it doesn't discard them. There's no good way to flush the old events, other than setting some global flag before undimming it, then calling ProcessSystemEvents to flush any queued event. You can then call ProcessSytemEvents again from the control2 callback if that flag is set, in order to flush additional events, and so on, swallowing each event until they stop coming. Then you can clear your flag from the control1 callback so that future events don't get ignored. Or something like this.

 

[Update: replaced "does" with "doesn't" in the last paragraph]

Message 2 of 10
(4,461 Views)

Thanks Luis.

0 Kudos
Message 3 of 10
(4,456 Views)

Follow up questions if these are allowed 😉

 

1.  Are GUI control callbacks re-entrant?  i.e., if the app is executing the control1 callback, and events get processed due to ProcessSystemEvents call, and the user causes a second event on control1, does the control1 callback get re-entered or does the CVI RTE block it until the first invocation of the control1 callback returns?

 

2.  Are async timer callbacks handled the same way as GUI callbacks in re to process system events?  If the app is executing in the control1 callback, and no call to ProcessSytemEvents is made, are async callbacks blocked until the control1 callback returns?

 

3.  If I have two async timers and a separate callback for each, are these callbacks necessarily mutually exclusive?  Since all async timer callbacks run on the same thread, am I guaranteed that if, say, timercallback1 has been invoked, that timercallback2 won't get invoked until timercallback1 returns?  Might this be true even if ProcessSystemEvents is called from within timercallback1? 

 

Thanks.

0 Kudos
Message 4 of 10
(4,429 Views)

1.  Are GUI control callbacks re-entrant?  i.e., if the app is executing the control1 callback, and events get processed due to ProcessSystemEvents call, and the user causes a second event on control1, does the control1 callback get re-entered or does the CVI RTE block it until the first invocation of the control1 callback returns?

Yes, they are reentrant. If you call ProcessSystemEvents in a callback, you could very well end up in nested control callbacks in the same thread. The only exception to this is EVENT_TIMER_TICK. All UI timer events are serialized, reagardless of which control sends the event.

 

2.  Are async timer callbacks handled the same way as GUI callbacks in re to process system events?  If the app is executing in the control1 callback, and no call to ProcessSytemEvents is made, are async callbacks blocked until the control1 callback returns?

Async timer callbacks are independent of ProcessSystemEvents. Because they are asynchronous, you don't need to call ProcessSystemEvents in order to dispatch an async timer event. Nor does calling ProcessSystemEvents have any influence on the likelhood of an async timer event firing. So, yes, an async timer can very well be sent to its  callback while the main thread is in some other callback.

 

3.  If I have two async timers and a separate callback for each, are these callbacks necessarily mutually exclusive?  Since all async timer callbacks run on the same thread, am I guaranteed that if, say, timercallback1 has been invoked, that timercallback2 won't get invoked until timercallback1 returns?  Might this be true even if ProcessSystemEvents is called from within timercallback1?

Yes, in Windows, all async timer callbacks do run in the same thread, therefore they are serialized. Note that this is not the case in Real-Time and in Linux. Calling ProcessSystemEvents has no effect on async timers.

 

Luis

Message 5 of 10
(4,406 Views)

Just out of curiosity, I have always been puzzled by this sentence found in ProcessSystemEvent online help:

LabWindows/CVI automatically updates the user interface in GetUserEvent or when a callback returns.

 

I suppose it refers to a control callback, but is this true for every event? If this is true for EVENT_MOUSE_POINTER_MOVE too, it means that simply moving the mouse on the user interface may cause pending draw events to be processed. This may have drowbacks in case of applications that intentionally want to leave the user interface frozen at a given moment while executing other tasks.



Proud to use LW/CVI from 3.1 on.

My contributions to the Developer Community
________________________________________
If I have helped you, why not giving me a kudos?
0 Kudos
Message 6 of 10
(4,394 Views)

Thanks Luis.

 

I guess I'm a little surprised that for a given control, the callback for that control is re-entrant - so that if the user causes two commit events on the same control, and the callback processes system events, that the second commit event could then run and re-enter the control callback before the first commit event callback has been completed.  I.e., callbacks are not serialized for commit events on a given control.

 

You could say, well, then don't do that - don't allow event processing in the callback.  But, sometimes you need to, to allow an abort control to get processed is a typical scenario.  As it is, if you provide for this, then you must also handle re-entry for the callback.

 

So how does one "debounce" or prevent this situation?  If you immediately dim the control on entry into the callback, does this guarantee the callback won't get re-entered before it either completes or allows event processing?  Since it's the same thread (main thread let's say) then it would seem that would do the trick.    If draw events get processed you'd see the control dim but otherwise not (so long as you undim prior to callback exit) based on your earlier answer, and the control would be momentarily disabled and callbacks delayed or prevented.

 

I should search the knowledge base, I seem to recall a discussion on control debounce.  I believe I've seen commercial apps exhibit debounce behavior - you can get the GUI control to double click (you see the control move twice) yet it's debounced and there's only one commit event processed.

 

Another trick is to remove the callback from the control from within the callback, but I'm not sure you can do this with a GUI control - I do this all the time with async timer callbacks and it seems to work OK.

0 Kudos
Message 7 of 10
(4,383 Views)

Roberto,

 

The assumption behind that sentence is that whenever your program is not executing inside a callback function, it is executing within a call to RunUserInterface, ProcessSystemEvents or GetUserEvent. These functions are always processing events, in between invocations of various callbacks. Therefore, as soon you leave the callback function, the expectation is that events will be processed very shortly thereafter.

 

Luis

0 Kudos
Message 8 of 10
(4,377 Views)

Menchar,

 

Without knowing your exact objectives for your application, it's hard for me to suggest how you should work around it.

 

I don't know if the event that would nest, in your case, would be exactly the same event as the original event, with the same event data, and thus potentially cause some infinite recursion until you hit a stack overflow. Yes, this situation can happen, but that is something that is in your power, as the programmer, to avoid. You can use any number of mechanisms to prevent this recursion, starting with simple global flags, to more sophisticated locking mechanisms.

 

But the point is, the semantics of ProcessSystemEvents are that it should dispatch queued events, no matter where it is called from. To do this, we have to be able to send an event to any callback, including the very same callback function in which ProcessSystemEvents is called from. To not do so would be unnecessarily (and artificially) limiting. Keep also in mind that multiple controls can share the same callback function, and so the "reentrant" event might not even be associated with the same control as the original event. Nor does it have to be the same event at all.

 

Here's a quick example:

 

In some control callback, let's assume that you handle a mouse left-click event by perfoming some time consuming operation. During this operation you call ProcessSystemEvents. Now, let's say that the user had double-clicked on some control in the panel. First, the left click is sent to your callback, and you respond to it by executing some code. By the time you call ProcessSystemEvents, the user had already clicked the button a second time, thus queueing up the corresponding double-click event. What will happen then is that the double-click event will "reenter" the same callback, as soon as you call ProcessSystemEvents. This behavior is definitely by design, and for CVI to block it would be incorrect, in my opinion. Now, this doesn't stop you from blocking it, based on some logic of your choice in your code. But it's better for you to have the possibility to do or not do this, than it would be to not even give you the choice to do so.

 

Dimming the control upon entry to the callback can reduce the likelihood of this happening, but it's no guarantee, since both events might have already been queued up by the time that your callback is called (depending on the type of event -- it's easier for this to happened with deferred callback events)

 

Luis

0 Kudos
Message 9 of 10
(4,375 Views)

Roberto,

 

Sorry, I overlooked the second part of your post.

 

1. Yes, this applies to all events.

 

2. If you are executing RunUserInterface, and you want to freeze your application's UI, you really cannot afford to exit the callback. Once the callback exits, you cannot assume that your application's UI won't change as a result of changes that you had made earlier. If you really need to do this, then you have to control the entirety of the execution thread -- in other words, you have to remain in the same callback. Otherwise, you shouldn't be in a RunUserInterface call. The alternative to using RunUserInterface is to call ProcessSystemEvents at certain times, only when you are willing to "unfreeze" the UI. But of course, this implies that your UI will also appear unresponsive to user input outside of those times.

Having said that, you can "freeze" canvas controls by using the canvas batch drawing functions, and you can also freeze graph controls by using ATTR_REFRESH_GRAPH. But these are the only exceptions I can think of.

 

Luis

0 Kudos
Message 10 of 10
(4,372 Views)