【问题标题】:Matlab gui WindowButtonMotionFcn crashes when called too often?Matlab gui WindowButtonMotionFcn 在调用太频繁时崩溃?
【发布时间】:2013-12-06 15:16:37
【问题描述】:

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

【问题讨论】:

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


    【解决方案1】:

    当一个回调被高频率调用时,它可能会在另一个调用完成之前被再次调用(即re-entrancy)。有了WindowButtonMotionFcn,这很有可能会发生。

    您可以通过检查函数调用堆栈(dbstack 的输出)是否有多​​次调用负责的回调来防止回调重新进入。 in a post on undocumentedmatlab.com 提供了一个非常简单但巧妙的检查实现,称为isMultipleCall。这个想法是计算回调函数名称出现在堆栈上的次数。直接从 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的用法很简单。将 run 它放在回调的顶部(在本例中为 hover_Callback),如果它指示多个调用正在进行中,则退出:

    function hover_Callback(hObject, eventdata, handles)
    
    if isMultipleCall();  return;  end
    
    ...
    
    end
    

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


    alternative approach 是使用listener 作为WindowButtonMotionEvent

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

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

    如果您没有使用 GUIDE 并且没有由guidata 管理的handles 结构,则调用类似motionListener 的侦听器并使用setappdata 来存储侦听器。例如,

    setappdata(hFigure,'mouseMotion',motionListener);
    

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


    顺便说一句,请注意axes 命令相当慢,可以通过将轴句柄直接传递给plot 来避免:

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

    【讨论】:

    • @Leo 欢迎您。我很高兴它成功了——我不确定这是否会成功。
    • 这是即时的错误缓解 :)
    猜你喜欢
    • 2011-05-18
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-10-30
    • 1970-01-01
    • 1970-01-01
    • 2014-10-29
    相关资源
    最近更新 更多