想知道标题中的问题是如何实现的。我有一些从按钮按下的回调。这些回调,如果被数字关闭中断,将导致错误,因为函数似乎运行,然后被关闭图形的关闭函数中断,然后回调似乎在数字关闭后恢复。
如果我将按钮的'Interruptible'
属性设置为'on'
,它会阻止其他回调中断它,但似乎不适用于该数字的关闭功能。我的另一个想法是在figuring的'closefunction'
回调中指定'CloseRequestFcn'
,然后在删除数字之前调用drawnow
来刷新事件队列,但这不起作用。
对我而言,最后一种方法是在运行回调时简单地将数字'CloseRequestFcn'
设置为''
,但这似乎很乏味。有没有标准的解决方案来实现这一目标?
编辑:
来自matlab的文档:
注意如果中断回调是DeleteFcn或CreateFcn 它的回调或数字的CloseRequest或ResizeFcn回调 无论其值如何,都会中断正在执行的回调 对象的可中断属性。中断回调开始 在下一个drawow,figure,getframe,pause或waitfor执行 声明。一个数字的WindowButtonDownFcn回调例程,或者 对象的ButtonDownFcn或Callback例程按照处理 上述规则。
所以似乎interruptible
属性不会影响close函数。
编辑2:
好的,所以我觉得我发现了一个问题。这真的很奇怪。我实际上从matlab文档中发现,如果将interruptible
属性设置为on
AND并且回调只是可中断的,那么:
If there is a drawnow, figure, getframe, waitfor, or pause command in the running callback, then MATLAB executes the interrupting callbacks which are already in the queue and returns to finish execution of the current callback.
我没有明确地使用这些函数中的任何一个,因此事实证明我的大多数回调都不能被closereqfcn
中断。但是,事实证明有些是,并且原因看起来很奇怪。如果有回调:
`大计算 - > imshow - > imshow
large computation -> set -> set -> set -> set
set
命令将轴visible
属性设置为off
,如果我在回调期间退出,则不会出现中断
现在,如果我有:
large computation -> imshow -> set -> imshow -> set
set
命令的回调期间退出,matlab会发出错误。另外,如果我有:
large computation -> imshow -> imshow -> set
set
命令的回调期间退出,matlab会发出错误。
large computation -> imshow -> imshow -> imshow
也会在第三个imshow
上发出错误。
出于某种原因,似乎连续两次调用imshow
会使我的回调中断。如果你使用多个drawnow
s,matlab是否可以隐式调用imshow
或做一些奇怪的事情?顺便说一句,我的matlab版本是R2009a。
答案 0 :(得分:2)
我从未真正相信Interruptible
旗帜(或类似的机制)......我马上承认我从未使用过它,但那是因为当我第一次尝试它时,我注意到了'Interruptible'
,'off'
(以及朋友)似乎对规则有更多例外而不是对它的辩护 - 头痛物质警报!
所以,我养成了通过使用标志来解决这类问题的习惯,并且在锁定/释放函数中包装必须真正不可中断的所有回调。
这样的事情:
% Define a button
uicontrol(...
'style', 'pushbutton',...
'interruptible', 'off',... % Nice, but doesn't catch DeleteFcn, CreateFcn, ...
% CloseRequestFcn or ResizeFcn
% ...
% further definition of button
% ...
% Put callback in a wrapper:
'callback', @(src,evt) uninterruptibleCallback(@buttonCallback, src,evt)...
);
其中uninterruptibleCallback()
看起来像这样:
function varargout = uninterruptibleCallback(callback, varargin)
% only execute callback when 'idle'
% (you can omit this if you don't want such strict ordering of callbacks)
while ~strcmp( get(mainFigure, 'userData'), 'idle' )
pause(0.01);
% ...or some other action you desire
end
% LOCK
set(mainFigure, 'userData', 'busy');
try
% call the "real" callback
[varargout{:}] = callback(varargin{:});
% UNLOCK
set(mainFigure, 'userData', 'idle');
catch ME
% UNLOCK
set(mainFigure, 'userData', 'idle');
throw(ME);
end
end
允许您将此closeReqFcn()
用于您的数字:
function closeReqFcn(~,~)
% only when the currently running locked callback (if any) has finished
while ~strcmp( get(mainFigure, 'userData'), 'idle' )
pause(0.01);
% ...or some other action you desire
end
% ...
% further clean-up tasks
% ...
% deletion
delete(mainFigure);
end
理论上,当您将所有回调放在这种模式中时,它基本上等于管理您自己的事件队列。
这当然有一些优点,但有很多很多缺点 - 你可能想要考虑一下这一点。对于您的用例,这整个机制可能会慢得令人无法接受,或者您可能需要定义更多具有更具体行为的锁定函数。
无论如何,我怀疑这是一个开始的好地方。
答案 1 :(得分:0)
@Rody Oldenhuis解决方案的替代方案是在CloseRequestFcn
内启动一个计时器,以便在没有不间断代码正在进行时关闭数字(可以用标志Closing_Allowed
表示)。 / p>
function mainFig_CloseRequestFcn(hObject, eventdata, handles)
Time = 3; % Wait time before force killing (in sec)
Kill.tmr = timer('executionMode', 'fixedRate',...
'Period', 1/10,...
'TimerFcn', {@KillingTimer_Callback, handles});
Kill.counts = ceil(Time/Kill.tmr.Period);
setappdata(handles.mainFig,'Kill',Kill);
start(Kill.tmr);
function KillingTimer_Callback(hObject, eventdata, handles)
Kill = getappdata(handles.mainFig,'Kill');
Kill.counts = Kill.counts - 1; % Count down
setappdata(handles.mainFig,'Kill',Kill);
if Kill.counts == 0 || getappdata(handles.mainFig, 'Closing_Allowed')
stop(Kill.tmr);
delete(handles.mainFig);
end
if Kill.counts == 0
表示超时,即使正在进行不间断任务也会关闭该数字,这会导致您现在有时会遇到相同的错误,但如果您知道完成不间断工作所需的最长时间,然后您可以正确设置上面的Time
。
最后通过设置Closing_Allowed
标志来包装不间断代码。
function pushbutton_Callback(hObject, eventdata, handles)
setappdata(handles.mainFig, 'Closing_Allowed', 0); % Closing is not allowed
pause(2);
setappdata(handles.mainFig, 'Closing_Allowed', 1); % Closing is allowed