Matlab gui WindowButtonMotionFcn当调用太频繁时崩溃? [英] Matlab gui WindowButtonMotionFcn crashes when called too often?
问题描述
我已经设置 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 && ...
pos(1,2)> ylim(1)&& ...
pos(1,2)< ylim(2))
inside = true;
end
if〜within
return
end
ix = round(pos(1,1));
iy = round(pos(2,2));
axes(handles.axes2); cla; (挤压(t2(ix,iy,:)),挤压(d2(ix,iy,:))
axes(handles.axes3); cla; (挤压(t3(ix,iy,:)),挤压(d3(ix,iy,:))
axes(handles.axes4); cla; plot(squeeze(t4(ix,iy,:)),squeeze(d4(ix,iy,:))
这会导致我的GUI停止响应,没有错误代码。如果我然后退出它,并再次启动它的整个MATLAB停止响应。任何人都知道可能发生什么,如何解决这个问题?
当回调被高频率调用时,会有危险在另一个调用完成执行之前再次调用(即重新加入)。使用 WindowButtonMotionFcn
您可以通过检查函数调用堆栈(输出 a)来防止回调重新入侵。 http://www.mathworks.com/help/matlab/ref/dbstack.html =nofollow> dbstack
)负责回调。一个非常简单,但是聪明的实现这种检查称为 isMultipleCall
的在无公告matlab.com的一篇文章。这个想法是计算回调函数名在堆栈上出现的次数。直接从undocumentedmatlab.com获取实际函数,但它提取到以下:
function flag = isMultipleCall()
s = dbstack();
%s(1)对应于isMultipleCall
如果numel(s)<= 2,flag = false;返回; end
%将栈上的所有函数与调用者的名称进行比较
count = sum(strcmp(s(2).name,{s(:)。name}));
%是来电者?
if count> 1,flag = true; else flag = false; end
isMultipleCall
的用法非常简单。将其运行在回调的顶部(在这种情况下, hover_Callback
),如果它指示正在进行多个调用,则退出:
function hover_Callback(hObject,eventdata,handles)
if isMultipleCall返回; end
...
end
这防止回调完全执行,直到先前的呼叫终止。只有检查将运行,跳过密集的图形对象操作(即 axes
, plot
等) p>
替代方法 是使用监听器进行 WindowButtonMotionEvent
:
handles.motion = handle.listener(gcf,'WindowButtonMotionEvent ',@ hover_callback2);
然后在回调中检查 eventdata.CurrentPoint
属性,而不是 currentpoint
。
如果您没有使用GUIDE,并且没有一个处理
结构管理 guidata
,然后调用侦听器类似 motionListener
并使用 setappdata
来存储监听器。例如,
setappdata(hFigure,'mouseMotion',motionListener);
只需使用GUI中任何对象的已知句柄,所以监听器仍然存在。您也可以使用 UserData
代替setappdata,或任何其他管理GUI数据的方式。
另外,请注意 axes
命令相当慢,可以通过直接将轴句柄传递到 plot
来避免:
plot(handles.axes2,squeeze(t2(ix,iy,:)),squeeze(d2(ix,iy,:))
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,:)));
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?
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.
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
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
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);
Then in the callback, check the eventdata.CurrentPoint
property instead of currentpoint
. Check for re-entrancy as above.
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);
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.
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屋!