Block GUI in Callback

조회 수: 9 (최근 30일)
Torsten Knüppel
Torsten Knüppel 2020년 4월 23일
댓글: Rik 2020년 4월 28일
Dear all,
how can I block interaction with a GUI, while a callback is executed. I'd like to create a GUI where by clicking a button a dialog to select a file opens and afterwards something is done to the file that is pretty time-consuming. Suprisingly, the callback is somehow executed in parallel, so it doesn't automatically block execution and this leads to undesired behaviour, because you could open the file-open-dialog again and I'd prefer to make this less annoying.
For illustration I created a small class:
classdef testGUI < handle
properties(Access = private)
hMainFigure
end
methods(Access = public)
function this = testGUI()
this.hMainFigure = figure('Visible', 'off');
uicontrol('Style', 'pushbutton', 'String', 'Test', 'Callback', @this.testCallback, 'Parent', this.hMainFigure, 'Units', 'normalized', 'Position', [0,0,1,1]);
this.hMainFigure.Visible = 'on';
end
end
methods(Access = private)
function testCallback(~, ~, ~)
% -- deactivate main figure
pause(2);
% -- activate main figure
fprintf('test\n');
end
end
end
If you click the button, the callback is executed and you can immediately click the button again - I would like to block the entire GUI until the callback (here the pause) is finished.
Thanks in advance,
Torsten

채택된 답변

Geoff Hayes
Geoff Hayes 2020년 4월 23일
Torsten - you could disable the button so that it can't be pressed again
function testCallback(~, hButtonObj, ~)
% -- deactivate main figure
set(hButtonObj, 'Enable', 'off'); % <----- disable button
pause(2);
% -- activate main figure
fprintf('test\n');
set(hButtonObj, 'Enable', 'on'); % <----- enable button
end
Of course, if you have several buttons or fields, you would need to block all of them too. Or consider using a Indeterminate Progress Bar....I think it is modal so while it is present, the user shouldn't be able to interact with your GUI.
  댓글 수: 6
Torsten Knüppel
Torsten Knüppel 2020년 4월 28일
Unfortunately, this didn't work as expected. If I return n in the above example, nothing changes.
Torsten Knüppel
Torsten Knüppel 2020년 4월 28일
I went with your first suggestions and introduced a small function to enable and disable all controls in a figure:
function disableGraphicsObjects(hGraphics, flag)
if(isprop(hGraphics, 'Enable'))
hGraphics.Enable = flag;
end
if(isprop(hGraphics, 'Children'))
for child = hGraphics.Children(:)'
disableGraphicsObjects(child, flag);
end
end
end
It does the trick for controls that are direct children of a figure - but I still need to test, if it also propagates to objects contained in a panel.

댓글을 달려면 로그인하십시오.

추가 답변 (1개)

Rik
Rik 2020년 4월 24일
편집: Rik 2020년 4월 24일
This is the way I solved it in my PhotoAnnotation tool:
%appdata is the guidata struct (which I now think was a poor choice as a name)
ButtonCallbackBuzy=appdata.ButtonCallbackBuzy;
if ButtonCallbackBuzy
return%ignore key presses if a callback is already in progress
else
appdata.ButtonCallbackBuzy=true;
guidata(appdata.fig,appdata);
end
You do need to carefully keep track of when you load and save the guidata struct.
It might be a better idea to write a getter and setter function to do it:
%in your functions that need to check if the busy flag is set:
if getIfBusyFlag(gcbf)
return%ignore
else
setIfBusyFlag(gcbf,true)
end
%long running code
setIfBusyFlag(gcbf,false)
%getter and setter
function isBusy=getIfBusyFlag(hfig)
isBusy=false;
if ~isappdata(hfig,'isBusy')
setappdata(hfig,'isBusy',isBusy);
else
isBusy=getappdata(hfig,'isBusy');
end
end
function setIfBusyFlag(hfig,isBusy)
setappdata(hfig,'isBusy',isBusy);
end
  댓글 수: 3
Torsten Knüppel
Torsten Knüppel 2020년 4월 28일
Very interesting suggestion, thanks a lot. But I went with something along the lines of Geoff's first answer - because your idea was not really applicable in my case (at least not so easily). I have a button that loads a file and a couple of controls to change parameters. On the one hand, if these parameters are changed the data from the file is processed and on the other hand, the ranges of the controls are affected by the data in the file. So I really would like to disable the entire GUI until the file is loaded, so that all values can be properly set and I don't run into an inconsistent state. Following your idea, I could introduce a flag "fileIsLoading" that I check whenever something is changed, but that would probably mean quite some overhead, that I'd like to avoid.
Rik
Rik 2020년 4월 28일
That is of course your call, although I doubt this will cause a lot of overhead. You could time how long these function take, but it is up to you to decide if that performance penalty is worth it.

댓글을 달려면 로그인하십시오.

카테고리

Help CenterFile Exchange에서 Environment and Settings에 대해 자세히 알아보기

제품


릴리스

R2018a

Community Treasure Hunt

Find the treasures in MATLAB Central and discover how the community can help you!

Start Hunting!

Translated by