02-19-2007 03:20 AM - edited 02-19-2007 03:20 AM
Message Edited by DocEye on 02-19-2007 03:26 AM
02-19-2007 04:06 AM
Some draw functions are not executed if called inside one callback until you exit the callback. This is not the case of SetCtrlVal which forces a redraw each time is called, but for example SetCtrlAttribute normally is not executed unless you explicitly force the entire UIR to be redrawn with ProcessDrawEvents () function: you try inserting this call immediately after hiding / displaying the graph.
Just for completness, to force all system events to be processed you can use ProcessSystemEvents () function. This one should not be necessary in your callback and could introduce some unexpected problem since all pending events are processed in this moment, so it must be used with caution. The reason for this function to exist is for example to permit sensing a button press when your function is tied in a loop which is long lasting; keep in mind, though, that the callback paradigm should be to have callback functions as short as possible exactly to permit normal processing of system events. Long-lasting functions should be designed other way (e.g. with timed state machines or separate threads).
08-25-2015 11:44 AM
Sorry this thread is so old. It's the very closest to my symptoms I could find on this forum. And Roberto's help is nearly getting me there.
Here's what I have in my application. I have a long-running data capture function. It looks something like this:
for (i=0; i<=nseg; i++) { j = address + i; DoStuff(j); // build a status string sprintf(indexDesc, "wrote '%i' to address 0x%X (0d%d)", cal[i], j, j); // update status index = i; fresh = TRUE; }
This function take s a while. My global variables index and fresh are a "poor man's" attempt at passing live looping updates to the caller of this function.
I do this by first creating an async timer that can then report the status. It looks like this:
int CVICALLBACK StatusTimer (int reserved, int timerId, int event, void *callbackData, int eventData1, int eventData2) { switch (event) { case EVENT_TIMER_TICK: //------------------ // section info //------------------ // only display new section info once if (lastSection != section) { // print step in messages sprintf(stemp, "%step %i", section + 1); SetCtrlVal(progressPanel,STATUS_TEXT,stemp); // update progress bar for some sections switch (section) { case 1: case 3: SetCtrlAttribute(progressPanel,PROGRESS_BAR,ATTR_VISIBLE,TRUE); SetCtrlAttribute(progressPanel,PROGRESS_BAR,ATTR_MARKER_STYLE,VAL_FULL_MARKERS); SetCtrlAttribute(progressPanel,PROGRESS_BAR,ATTR_TICK_STYLE,VAL_FULL_TICKS); SetCtrlAttribute(progressPanel,PROGRESS_BAR,ATTR_MAX_VALUE,maxIndex); // help GUI ProcessDrawEvents(); break; default: SetCtrlAttribute(progressPanel,PROGRESS_BAR,ATTR_VISIBLE,FALSE); // help GUI ProcessDrawEvents(); break; } // make these changes now ProcessSystemEvents(); // update section state lastSection = section; // help GUI ProcessDrawEvents(); } //------------------ // loop index info //------------------ // only display fresh data if (fresh) { // update progress bar for some sections switch (section) { case 1: case 3: SetCtrlVal(progressPanel,PROGRESS_BAR,index); // echo step detail in messages sprintf(stemp, "%s", indexDesc); SetCtrlVal(progressPanel,STATUS_TEXT,stemp); break; default: break; } // make these changes now ProcessSystemEvents(); // clear flag fresh = FALSE; // help GUI ProcessDrawEvents(); } break; } return 0; }
But what I'm seeing is that the SetCtrlVal calls update immediately (like Roberto said), whereas the SetCtrlAttribute calls do not, until the complete loop call finishes.
Even after adding the ProcessDrawEvents, or even ProcessSystemEvents, I don't see them. Is there some other way of forcing a redraw of the UIR?
08-25-2015 12:51 PM
At a first glance to the code you published, I noticed that each call to SetCtrlVal addresses STATUS_something controls, while the calls to SetCtrlAttribute address PROGRESS_BAR control: they cannot be in the same panel!
It may be a typo in pasting the code, but double check this just to be sure...
08-25-2015 01:30 PM
Ah, indeed. You are right, these were problems in my copy/paste. I didn't want to paste as-is from my actual source, due to IP concerns here. In the actual code, the two controls are indeed on the same panel.
After some time, and reviewing your comment here: http://forums.ni.com/t5/LabWindows-CVI/SetCtrlAttribute-only-works-during-debug/m-p/54474#M4842
... I found my problem. It really just amounted to more careful placement of the ProcessDrawEvents calls. I didn't have to use any ProcessSystemEvents.
Thanks.
08-25-2015 03:23 PM
Ok, I was suspecting this wasn't the reason but I pointed you to it just in case. I sometimes fall into this kind of error when dealing with complex projects.
I'm happy you solved your problem.
08-25-2015 03:31 PM
I wonder whether this framework could be simplified someway getting rid of the timer and the global flags: if you are using the timer only to update the user interface you could PostDeferredCall a function from inside the loop to update the UI when a cycle is terminated. If a ProcessSystemEvents already exists in your loop, the main thread will execute the deferred function and update the UI only when needed.
This could interfere with other parts of your application so forgive it if you don't want/cannot use it.
08-26-2015 07:30 AM
Yeah, I was using PostDeferredCall for a while, but ultimately sought a different way, mostly because the above is going into a DLL. So it needs to be as portable as possible. I need the caller to build their own indication mechanism of the loop status.
For now, what I have is sufficient I think. Thanks for your help!