我已将WindowButtonMotionFcn
设置为我的回调,其中绘制了三个图,数据取决于鼠标位置。然而,这对于MATLAB来说似乎太过分了,因为在将鼠标移动一点之后,GUI就会停止响应。
我使用此代码(从某人复制的部分):
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停止响应。任何人都知道会发生什么以及如何解决这个问题?也许我在某种程度上堵塞了我的记忆?
答案 0 :(得分:2)
当以高频率调用回调时,存在在另一个呼叫完成执行之前将再次调用它的危险(即re-entrancy)。使用WindowButtonMotionFcn
,这将是一个很有可能发生这种情况。
您可以通过检查函数调用堆栈(dbstack
的输出)来对负责的回调进行多次调用来阻止回调重入。这个名为isMultipleCall
的检查是一个非常直接但聪明的实现in a post on undocumentedmatlab.com。我们的想法是计算回调函数名称在堆栈中出现的次数。直接从undocumentedmatlab.com获取实际功能,但它提炼出以下内容:
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
的使用非常简单。把它放在回调的顶部(在这种情况下,hover_Callback
),如果它表明正在进行多个调用,则将其挽救:
function hover_Callback(hObject, eventdata, handles)
if isMultipleCall(); return; end
...
end
这可以防止回调在先前的调用终止之前再次完全执行。只会运行检查,跳过密集的图形对象操作(即axes
,plot
等。)
alternative approach 是WindowButtonMotionEvent
使用listener:
handles.motion = handle.listener(gcf,'WindowButtonMotionEvent',@hover_callback2);
然后在回调中,检查eventdata.CurrentPoint
属性而不是currentpoint
。检查上面的重新入侵。
如果您没有使用GUIDE且没有handles
guidata
管理的motionListener
结构,请调用类似setappdata
的侦听器并使用setappdata(hFigure,'mouseMotion',motionListener);
存储侦听器。例如,
UserData
只需使用GUI so the listener persists中任何对象的已知句柄即可。您也可以使用axes
代替setappdata或any other way of managing GUI data。
顺便说一句,请注意plot
命令相当慢,可以通过直接将轴句柄传递给plot(handles.axes2, squeeze(t2(ix,iy,:)), squeeze(d2(ix,iy,:)));
来避免:
{{1}}