Matlab gui WindowButtonMotionFcn 在调用太频繁时崩溃? [英] Matlab gui WindowButtonMotionFcn crashes when called too often?
问题描述
我已将 WindowButtonMotionFcn
设置为我的回调,它绘制三个图,数据取决于鼠标位置.然而,这对 MATLAB 来说似乎太多了,因为在移动我的鼠标一点之后,GUI 停止响应.
I've set WindowButtonMotionFcn
to my callback which plots three plots, with the data depending on mouse position. However this seems to be too much for MATLAB to handle, because after moving my mouse around a bit, the GUI stops responding.
我使用此代码(从某人那里复制的部分):
I use this code (copied parts from someone):
set(handles.figure1, 'windowbuttonmotionfcn', @hover_Callback);
function hover_Callback(hObject, handles, eventdata)
inside = false;
pos = get(handles.axes1, 'currentpoint');
xlim = get(handles.axes1, 'XLim');
ylim = get(handles.axes1, 'YLim');
if (pos(1,1) > max(xlim(1), 1) && ...
pos(1,1) < xlim(2) && ...
pos(1,2) > ylim(1) && ...
pos(1,2) < ylim(2))
inside = true;
end
if ~inside
return
end
ix = round(pos(1,1));
iy = round(pos(2,2));
axes(handles.axes2); cla; plot(squeeze(t2(ix,iy,:)), squeeze(d2(ix,iy,:)));
axes(handles.axes3); cla; plot(squeeze(t3(ix,iy,:)), squeeze(d3(ix,iy,:)));
axes(handles.axes4); cla; plot(squeeze(t4(ix,iy,:)), squeeze(d4(ix,iy,:)));
这会导致我的 GUI 停止响应,但没有错误代码.如果我然后退出它并重新启动它,整个 MATLAB 将停止响应.任何人都知道会发生什么以及我该如何解决这个问题?可能是我的记忆有点卡住了?
This causes my GUI to stop responding, without error codes. If I then quit it and start it again the whole of MATLAB stops responding. Anyone knows what could be happening and how I can fix this? Maybe I'm somehow clogging my memory?
推荐答案
当一个回调被高频率调用时,有可能在另一个调用完成之前再次调用它(即重新进入).使用 WindowButtonMotionFcn
,有一个发生这种情况的可能性非常大.
When a callback is called with high frequency, there is the danger that it will be called again before another call has finished executing (i.e. re-entrancy). With WindowButtonMotionFcn
, there's a pretty darn good chance that this will happen.
您可以通过检查函数调用堆栈(dbstack
) 用于多次调用负责的回调.在 undocumentedmatlab.com 上的一篇文章中.这个想法是计算回调函数名称出现在堆栈上的次数.直接从 undocumentedmatlab.com 获取实际函数,但它提炼为以下内容:
You can prevent callback re-entrancy by inspecting the function call stack (the output of dbstack
) for multiple calls to the responsible callback. A very straightforward, but clever implementation of such a check called isMultipleCall
is presented in a post on undocumentedmatlab.com. The idea is to count the number of times the callback function name appears on the stack. Take the actual function directly from undocumentedmatlab.com, but it distills to the following:
function flag=isMultipleCall()
s = dbstack();
% s(1) corresponds to isMultipleCall
if numel(s)<=2, flag=false; return; end
% compare all functions on stack to name of caller
count = sum(strcmp(s(2).name,{s(:).name}));
% is caller re-entrant?
if count>1, flag=true; else flag=false; end
isMultipleCall
的用法很简单.将 run 它放在回调的顶部(在本例中为 hover_Callback
),如果它指示多个调用正在进行中,则退出:
The usage of isMultipleCall
is very simple. Put run it at the top of the callback (in this case, hover_Callback
), and bail out if it indicates that multiple calls are in progress:
function hover_Callback(hObject, eventdata, handles)
if isMultipleCall(); return; end
...
end
这可以防止回调完全执行,直到之前的调用终止.只会运行检查,跳过密集的图形对象操作(即 axes
、plot
等)
This prevents the callback from executing fully again until previous calls have terminated. Only the check will be run, skipping the intensive graphics object operations (i.e. axes
, plot
, etc.)
An alternative approach is to use a listener for the WindowButtonMotionEvent
:
handles.motion = handle.listener(gcf,'WindowButtonMotionEvent',@hover_callback2);
然后在回调中,检查 eventdata.CurrentPoint
属性而不是 currentpoint
.如上所述检查重新进入.
Then in the callback, check the eventdata.CurrentPoint
property instead of currentpoint
. Check for re-entrancy as above.
如果您不使用 GUIDE 并且没有由 guidata
管理的 handles
结构,则调用诸如 motionListener
之类的侦听器并使用setappdata
来存储监听器.例如,
If you are NOT using GUIDE and do not have a handles
structure managed by guidata
, then call the listener something like motionListener
and use setappdata
to store the listener. For example,
setappdata(hFigure,'mouseMotion',motionListener);
只需使用 GUI 中任何对象的已知句柄 这样监听器持续存在.您还可以使用 UserData
代替 setappdata,或任何其他管理 GUI 数据的方式.
Just use the known handle of any object in the GUI so the listener persists. You could also use UserData
instead of setappdata, or any other way of managing GUI data.
顺便说一句,请注意 axes
命令相当慢,可以通过将轴句柄直接传递给 plot
来避免:
As an aside, note that the axes
command is rather slow, and can be avoided by passing the axis handle to plot
directly:
plot(handles.axes2, squeeze(t2(ix,iy,:)), squeeze(d2(ix,iy,:)));
这篇关于Matlab gui WindowButtonMotionFcn 在调用太频繁时崩溃?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!