问题
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.
回答1:
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.
回答2:
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