While-loop in GUI ends when interacting with other GUI controls
조회 수: 3 (최근 30일)
이전 댓글 표시
Dear community
I am working on a very complex GUI that controls a group of instruments in a scientific facility. The GUI is in charge of communicating with three instruments via RS-232, query data and display it in a live plot. Let's call them Instruments A, B, and C. To control the devices, the GUI contains a whole bunch of buttons, menus, checkboxes, etc. for the three instruments.
In order to keep the plotting 'alive', the while loop queries a Global flag acquire which is assigned to the handles structure and updated at the end of every Callback using: guidata(hObject, handles)
global acquire; % Flag to keep the acquisition alive
acquire = 0; % Initial status of the acquisition flag
The live plotting function prototype looks like the following 'skeleton'. (Of course is way more complex than this, we are talking about ~600+ lines of actual code only in this function)
function [loggedData, timeGroup, handles] = liveDataCapture(handles, hObject)
% Before the loop starts there are a bunch of initializations...
while isequal(handles.flagAcq, 1)
% At every loop verify the status of the flag
handles.flagAcq = getFlagAcquisition;
...
...
%
%% Complex data acquisition routines, queries values from the 3 instruments, creates data arrays, timestamps, animatedlines, etc.
%
% Set legends according to the checkbox --> read description below
if isequal(get(handles.checkHideLegend, 'Value'), 1)
legend('Show')
else
legend('Hide')
end
end
%
% If the user presses a 'stopButton', then the flag is set to 0 with: handles.flagAcq = setFlagAcquisiton(0);
%
end
The only way to keep the while-loop running when interacting with one of the controls from, say Instrument A or the live plot itself, is by updating the global flag using a function that sets its value to 1. For instance, if I interact with the checkbox for showiing/hiding the graph legends inside the previous while-loop, I must update the global flag inside the checkbox Callback:
function checkHideLegend_Callback(hObject, eventdata, handles)
% Force the Global flag to keep its value of 1
setFlagAcquisiton(1);
handles.flagAcq = getFlagAcquisition;
value = get(hObject, 'Value');
if isequal(value, 1)
set(hObject, 'String', 'Hide Legend')
else
set(hObject, 'String', 'Show Legend')
end
guidata(hObject, handles) % Update the handles structure
return
Similarly, I have included the setFlagAcquisition(1) function in some controls from Instrument A.
Now, if I don't do this on the other controls (buttons, checkboxes, etc.) from Instruments B and C, the While-loop ends despite the value of handles.flagAcq is always 1. I have checked it in debugging mode already.
The main issue here is that I would have to do this for around 50+ controls and I have the feeling that this is NOT the right way to tell the GUI to keep the acquisition loop running if the user intracts with the instruments controls.
Questions:
- Is there a way to avoid using Global flags to keep the loop running until the user want to stop the live acquisition?
- Why the While-loop ends? Is it related to updating the handles structure when using: guidata(hObject, handles)
- Am I missing a property from the handles structure that will avoid the need of this global variable? (e.g. the Interruptible property, etc.)
Thank you in advance for your time
EDIT: Just to clarify, I have sucessfully used this Global flag approach on a previous GUI however, I understand that Global variables are generally not recommended.
댓글 수: 7
Jan
2021년 3월 11일
편집: Jan
2021년 3월 11일
I am NOT using any breaks or changing the conditions of the handles.flagAcq in any of those controls
This is the problem of global variables: It is hard to find out, from where they have been changed.
What about setting a breakpoint in setFlagAcquisiton to see, when the flag is dsiabled? Obviously there is a command, which resets the flag. Without seeing the complete code, it is impossible to guess, where this happens.
답변 (1개)
Jan
2021년 3월 11일
편집: Jan
2021년 3월 11일
I have an idea:
function checkHideLegend_Callback(hObject, eventdata, handles)
% When reaching this, the struct [handles] contains the value from the
% time point, when this callback has been created. This value is not
% updated dynamically.
% This means, that e.g. handles.flagAcq has the initial value.
% If you now call:
guidata(hObject, handles) % Update the handles structure
% directly, the current state of handles is replaced by the initial
% state.
For this reason I consider is as bad design to provide the handles struct as 3rd input argument. It is more clear, to obtain the current value dynamically:
function checkHideLegend_Callback(hObject, eventdata, handles_ignore)
handles = guidata(hObject);
...
guidata(jObject, handles);
end
See also: https://www.mathworks.com/matlabcentral/answers/57550-faq-incomplete-handles-struct-in-callbacks
Using this should replace the helper function setFlagAcquisiton(), but it is suffcient to store this flag directly in handles.flagAcq .
댓글 수: 3
Jan
2021년 3월 11일
@Rik: This is nice. I tried GUIDE in R2009a and gave up very soon. When the handles struct is updated dynamically already, me guess does not hit the point. Then anywhere in the code the flag must be set actively. The Debugger can reveal the location, when all callbacks are observed using break points.
참고 항목
카테고리
Help Center 및 File Exchange에서 Instrument Connection and Communication에 대해 자세히 알아보기
Community Treasure Hunt
Find the treasures in MATLAB Central and discover how the community can help you!
Start Hunting!