Matlab gui WindowButtonMotionFcn在经常调用时会崩溃吗?

我已经将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停止响应.任何人都知道会发生什么以及如何解决这个问题?也许我以某种方式堵塞了我的记忆?

最佳答案 当以高频率调用回叫时,存在在另一个呼叫完成执行(即
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

这可以防止回调在先前的调用终止之前再次完全执行.只运行检查,跳过密集的图形对象操作(即轴,图等)

alternative approach将使用listener作为WindowButtonMotionEvent:

handles.motion = handle.listener(gcf,'WindowButtonMotionEvent',@hover_callback2);

然后在回调中,检查eventdata.CurrentPoint属性而不是currentpoint.如上所述检查重新入侵.

如果您不使用GUIDE并且没有guidata管理的句柄结构,则调用侦听器类似于motionListener并使用setappdata存储侦听器.例如,

setappdata(hFigure,'mouseMotion',motionListener);

只需使用GUI so the listener persists中任何对象的已知句柄.您也可以使用UserData而不是setappdata或any other way of managing GUI data.

另外,请注意,axis命令相当慢,可以通过将轴手柄直接传递给绘图来避免:

plot(handles.axes2, squeeze(t2(ix,iy,:)), squeeze(d2(ix,iy,:)));
点赞