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

时间:2013-12-06 15:16:38

标签: matlab user-interface callback hover matlab-guide

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

1 个答案:

答案 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

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


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}}