MATLAB provides the addlistener
function.
Listeners allow us to keep track of changes of an object's properties and act upon them. For example, we can create a very simple listener that will display a message in the command window when the 'YLim'
property of an axes
object is changed:
% Example using axes
ax = axes();
addlistener(ax, 'YLim', 'PostSet', @(src, evnt)disp('YLim changed'));
Try panning the axes or zooming in/out and see what happens. This works fine.
I need to do the same but using an uiaxes
instead.
Unfortunately, it looks like we are not allowed to do so. Try running the following example:
% Example using uiaxes
ax = uiaxes();
addlistener(ax, 'YLim', 'PostSet', @(src, evnt)disp('YLim changed'));
It throws this error:
Error using matlab.ui.control.UIAxes/addlistener While adding a PostSet listener, property 'YLim' in class 'matlab.ui.control.UIAxes' is not defined to be SetObservable.
I've read the articles Listen for Changes to Property Values and Observe Changes to Property Values and I learned that a property must be declared as SetObservable
to allow being listened:
classdef PropLis < handle
properties (SetObservable)
ObservedProp = 1 % <-- Observable Property
end
end
I've tried taking a look at the UIAxes
class definition via edit matlab.ui.control.UIAxes
but it's not possible because it's a P-file.
If 'YLim'
is not observable then how can I keep track of changes in this property?
I'm using App Designer in MATLAB R2018b.
We should attach the listener to the internal Axes
object, and not the UIAxes
itself. Try this:
hFig = uifigure();
hAx = uiaxes(hFig);
addlistener(struct(hAx).Axes, 'YLim', 'PostSet', @(src, evnt)disp("YLim changed"));
hAx.YLim = [0 2];
In case anybody is wondering, I found this via trial and error.
Tested on R2018a & R2018b.
Thank you so much for this solution! I was having a real problem with zooming in on 3D data on a UIAxes. The 3D axes contained a .png background raster map at z=0 (plotted as a surface) and the 3D position of a UAV flight in x-y-x. When I would zoom in, the z would zoom as well and the new z limits would exclude the map I wanted always displayed. What was odd, is that setting
app.UIAxes2.Interactions = [zoomInteraction('Dimensions','xy')];
would correct the problem when zooming with the scroll wheel on my mouse, but if I selected the zoom toolbar button (clicking to zoom), it would still zoom in z. Really frustrating.
To get around this, I used your example, but added the listener to the 'ZLim' and made a callback function that would look at all the elements of the plot, and reset ZLim to include all the data whenever the ZLim changed.
warning('off','MATLAB:structOnObject');
addlistener(struct(app.UIAxes2).Axes, 'ZLim', 'PostSet', @(src,evnt)mapholdaltlims(app,app.UIAxes2));
function [inclusivezlim] = mapholdaltlims(app,ax)
objwithz = findobj(app.UIAxes2.Children,'-property','ZData');
currmin_z = 0;
currmax_z = 0;
for i = 1:length(objwithz)
currmin_z = min([min(min(objwithz(i).ZData)), currmin_z]);%Need double mins because data could be 2d surface
currmax_z = max([max(max(objwithz(i).ZData)), currmax_z]);
end
inclusivezlim = [currmin_z currmax_z];
ax.ZLim = inclusivezlim;
%disp('Updated the limits')
end
Man, what a pain this was. I am glad it now works. Thanks again.
来源:https://stackoverflow.com/questions/53825151/uiaxes-ylim-property-cannot-be-listened-to