addlistener Behavior/Syntax
4 visualizaciones (últimos 30 días)
Mostrar comentarios más antiguos
Peter Cook
el 1 de Feb. de 2018
Comentada: Peter Cook
el 2 de Feb. de 2018
I've got a listener on an axes object that listens for changes to either XLim or YLim and fires a callback based on the new axes limits. The callback executes correctly, but I've noticed that if both XLim and YLim are updated simultaneously that the callback executes twice (once when XLim is updated, and again when YLim is updated), regardless of axes property assignment syntax. I'd like to avoid this behavior - that is, if both XLim and YLim are updated, I'd only like the callback to fire once.
Axes Listener Class:
classdef dasAxesPropEvent < handle
properties(SetObservable, GetObservable, AbortSet)
XLim
YLim
end
methods
%constructor
function obj = dasAxesPropEvent(hAx)
%hAx is a handle object to the parent axes
obj.XLim = hAx.XLim;
obj.YLim = hAx.YLim;
addlistener(hAx,{'XLim','YLim'},'PostSet',@obj.handlePropEvent);
end
%gettor
function propval = get.XLim(obj)
propval = obj.XLim;
end
%gettor
function propval = get.YLim(obj)
propval = obj.YLim;
end
%settor
function set.XLim(obj,val)
obj.XLim = val;
end
%settor
function set.YLim(obj,val)
obj.YLim = val;
end
%overload disp
function disp(obj)
disp(class(obj))
end
%updator
function handlePropEvent(obj,src,evnt)
switch src.Name
case 'XLim'
obj.XLim = evnt.AffectedObject.XLim;
case 'YLim'
obj.YLim = evnt.AffectedObject.YLim;
otherwise
%?
end
end
end
end
In another object, I add a listener to a dasAxesPropEvent to fire the callback if the axes is updated. I use the listener class instead of a listener directly on the axes in order to use the AbortSet property.
hObj.axesListener = addlistener(hDasPropEvent,{'XLim','YLim'},'PostSet',@hObj.updateDasImage);
Here's an example of the behavior. I added some debug/print lines (dbstack, XLim, and YLim) to @hObj.updateDasImage.
> In dasImage/updateDasImage (line 205)
In dasImage>@(varargin)hObj.updateDasImage(varargin{:}) (line 182)
In dasAxesPropEvent/handlePropEvent (line 48)
In dasAxesPropEvent>@(varargin)obj.handlePropEvent(varargin{:}) (line 16)
In matlab.graphics.internal.LinkProp/processUpdate (line 30)
In localUpdateListeners>@(varargin)hLink.processUpdate(varargin{:}) (line 54)
In dtsDasWaterfall01>aufbauschen (line 3793)
In gui_mainfcn (line 95)
In dtsDasWaterfall01 (line 44)
In matlab.graphics.internal.figfile.FigFile/read>@(hObject,eventdata)dtsDasWaterfall01('aufbauschen',hObject,eventdata,guidata(hObject))
XLim
01-Nov-2017 12:33:24
01-Nov-2017 14:17:36
YLim
14.3882 985.0474
> In dasImage/updateDasImage (line 205)
In dasImage>@(varargin)hObj.updateDasImage(varargin{:}) (line 182)
In dasAxesPropEvent/handlePropEvent (line 50)
In dasAxesPropEvent>@(varargin)obj.handlePropEvent(varargin{:}) (line 16)
In matlab.graphics.internal.LinkProp/processUpdate (line 30)
In localUpdateListeners>@(varargin)hLink.processUpdate(varargin{:}) (line 54)
In dtsDasWaterfall01>aufbauschen (line 3793)
In gui_mainfcn (line 95)
In dtsDasWaterfall01 (line 44)
In matlab.graphics.internal.figfile.FigFile/read>@(hObject,eventdata)dtsDasWaterfall01('aufbauschen',hObject,eventdata,guidata(hObject))
XLim
01-Nov-2017 12:33:24
01-Nov-2017 14:17:36
YLim
15.6671 984.4080
The dbstack is nearly identical for both calls - the XLim listener callback fires before YLim is assigned, then the YLim listener callback fires.
The line where XLim & YLim are assigned is this:
set(handles.axes1,'XLim',newXLim,'YLim',newYLim);
The same behavior happens if I do serial assignment (except the dbstack entry point for aufbauschen is +1 line):
handles.axes1.XLim = newXLim;
handles.axes1.YLim = newYLim;
and also the same thing happens if I use deal:
[handles.axes1.XLim,handles.axes2.YLim] = deal(newXLim,newYLim);
In this scenario (XLim & YLim both updated) is it possible to make the callback execute only once? It is possibly relevant information that there is also a LinkProp listener on the same axes, which is why there's a call to LinkProp ahead of the call to handlePropEvent in the dbStack.
0 comentarios
Respuesta aceptada
Benjamin Kraus
el 1 de Feb. de 2018
There is no way to merge the two events into one event. Even when you call set, the properties are still set one at a time, in order.
In other words:
set(handles.axes1,'XLim',newXLim,'YLim',newYLim);
is effectively equivalent to:
handles.axes1.XLim = newXLim;
handles.axes1.YLim = newYLim;
In both versions, the XLim property is set first, followed by the YLim property. The PostSet listener for the XLim property has no way to know that you are about to set the YLim property, so it cannot suppress the first event while waiting for the YLim to be set.
3 comentarios
Benjamin Kraus
el 2 de Feb. de 2018
Editada: Benjamin Kraus
el 2 de Feb. de 2018
I'm curious why it matters whether the callback fires twice or not. Does the callback have some side-effect (such as incrementing a counter) that behaves differently if it is called too many times? Or is your concern related to performance?
Another way to solve your question may be to look at the callback and identify if there is some way to make it resilient to being triggered twice.
Más respuestas (0)
Ver también
Categorías
Más información sobre Specifying Target for Graphics Output en Help Center y File Exchange.
Community Treasure Hunt
Find the treasures in MATLAB Central and discover how the community can help you!
Start Hunting!