Undocumented Matlab
  • SERVICES
    • Consulting
    • Development
    • Training
    • Gallery
    • Testimonials
  • PRODUCTS
    • IQML: IQFeed-Matlab connector
    • IB-Matlab: InteractiveBrokers-Matlab connector
    • EODML: EODHistoricalData-Matlab connector
    • Webinars
  • BOOKS
    • Secrets of MATLAB-Java Programming
    • Accelerating MATLAB Performance
    • MATLAB Succinctly
  • ARTICLES
  • ABOUT
    • Policies
  • CONTACT
  • SERVICES
    • Consulting
    • Development
    • Training
    • Gallery
    • Testimonials
  • PRODUCTS
    • IQML: IQFeed-Matlab connector
    • IB-Matlab: InteractiveBrokers-Matlab connector
    • EODML: EODHistoricalData-Matlab connector
    • Webinars
  • BOOKS
    • Secrets of MATLAB-Java Programming
    • Accelerating MATLAB Performance
    • MATLAB Succinctly
  • ARTICLES
  • ABOUT
    • Policies
  • CONTACT

Property value change listeners

August 13, 2014 14 Comments

For performance reasons, it is almost always better to respond to events (asynchronously), than to continuously check a property value (synchronous polling). Therefore, if we wish to do something when some property value is changed (e.g., log the event, shut down the system, liquidate the portfolio, call the police, …), then it is preferable to attach a property-change listener callback.
The standard (documented) way of attaching a value-change listener to Matlab class properties is via the addlistener function. This only works for handle (not value) classes, and only to those properties that have the SetObservable and/or GetObservable attribute turned on:

addlistener(hClassObject, propertyName, 'PostSet', @myCallbackFcn);

addlistener(hClassObject, propertyName, 'PostSet', @myCallbackFcn);

This is all nice and well for Matlab class properties, but what about HG (handle Graphics: plots & GUI) properties? Can we similarly listen to changes in (say) the axes limits? Until now this has been possible, but undocumented. For example, this will trigger myCallbackFcn(hAxes,eventData) whenever the axes limits change (due to zoom, pan, plotting etc.):

addlistener(gca, 'YLim', 'PostSet', @(hAxes,eventData) myCallbackFcn(hAxes,eventData));
% Or (shorter equivalent):
addlistener(gca, 'YLim', 'PostSet', @myCallbackFcn);

addlistener(gca, 'YLim', 'PostSet', @(hAxes,eventData) myCallbackFcn(hAxes,eventData)); % Or (shorter equivalent): addlistener(gca, 'YLim', 'PostSet', @myCallbackFcn);

This could be very useful when such properties could be modified from numerous different locations. Rather than updating all these location to call the relevant callback function directly, we simply attach the callback to the property-change listener. It could also be useful in cases where for some reason we cannot modify the source of the update (e.g., third-party or legacy code).
In addition to PostSet, we could also set listeners for PreSet. Also, we could set listeners on PostGet and PreGet – this could be useful for calculating dynamic (dependent) property values.

Under the hood

The HG1 variant of addlistener is basically equivalent to the following low-level UDD-based code snippet, as explained here:

% Create the listener object
hAxes = handle(gca);  % a UDD axes class object
hProp = findprop(hAxes,'YLim');  % a schema.prop class object
hListener = handle.listener(hAxes, hProp, 'PropertyPostSet', @myCallbackFcn);
% persist the listener in memory for as long as the source object (hAxes) is alive
setappdata(hAxes, 'listener__', hListener);

% Create the listener object hAxes = handle(gca); % a UDD axes class object hProp = findprop(hAxes,'YLim'); % a schema.prop class object hListener = handle.listener(hAxes, hProp, 'PropertyPostSet', @myCallbackFcn); % persist the listener in memory for as long as the source object (hAxes) is alive setappdata(hAxes, 'listener__', hListener);

(in old Matlab releases, addlistener was a regular m-function that placed the listeners in the source handle’s ApplicationData property, as the code above shows; newer releases reimplemented addlistener as an internal built-in function and the listener is now stored somewhere in the DLL’s inaccessible memory, rather than in the ApplicationData property)
In HG2, handle.listener no longer works. Fortunately, we don’t need it since we have addlistener that works the same way for both HG1 (UDD objects) and HG2 (MCOS objects). Kudos on the backward-compatibility aspect, MathWorks!

Related posts:

  1. UDD Events and Listeners – UDD event listeners can be used to listen to property value changes and other important events of Matlab objects...
  2. copyobj behavior change in HG2 – the behavior of Matlab's copyobj function changed in R2014b (HG2), and callbacks are no longer copied. ...
  3. Setting class property types – Matlab's class properties have a simple and effective mechanism for setting their type....
  4. Handle object as default class property value – MCOS property initialization has a documented but unexpected behavior that could cause many bugs in user code. ...
  5. Getting default HG property values – Matlab has documented how to modify default property values, but not how to get the full list of current defaults. This article explains how to do this. ...
  6. xlsread functionality change in R2012a – The functionality of the xlsread function has changed without documentation or warning in the R2012a release. ...
GUI Handle graphics HG2 schema.prop Undocumented feature
Print Print
« Previous
Next »
14 Responses
  1. David September 2, 2014 at 12:55 Reply

    You can also call the event.proplistener constructor directly instead of using add listener which creates a listener not tied to the lifecycle of the object being listened to.

    http://www.mathworks.co.uk/help/matlab/ref/event.proplistener.html

    • Yair Altman September 2, 2014 at 13:01 Reply

      @David – I think you have it backwards: event.proplistener creates a standalone listener that is not tied to the object’s lifecycle. This means that it works only as long as the listener variable is in memory (not cleared). In order to persist it to live as long as the object, the typical use would be to store this listener in the object’s UserData or ApplicationData properties.

      On the other hand, addlistener already does all this for us. It is therefore both easier and safer to use.

    • David September 2, 2014 at 13:33 Reply

      Hi Yair,

      Maybe there should have been a comma or two in my original statement to avoid confusion as we are definitely both talking about the same thing. Typical usage (assuming we are all using OOP) would be to store the event.listener/event.proplistener as a property in the class where it was created. In my applications I almost always use event.listener and event.proplistener as advised by MathWorks.

      Revised:
      “You can also call the event.proplistener constructor directly, instead of using addlistener, which creates a listener not tied to the lifecycle of the object being listened to.”

      • David September 2, 2014 at 13:38

        Or put another way…

        “Instead of using addlistener you can call the event.proplistener constructor directly which creates a listener not tied to the lifecycle of the object being listened to”.

  2. John September 10, 2014 at 09:17 Reply

    Yair,

    Is it possible using this method or others to listen to properties that are not considered observable? My example is that I’d like to listen for, and respond to, changes to a figure’s ‘Position’ property. Ordinarily I trigger this by using ResizeFcn, but in this case I want the behavior to be triggered afterwards.

    I tried (from memory…)

    lh = addlistener(fignum, 'Position', 'PostSet', @mypostresizefcn);

    lh = addlistener(fignum, 'Position', 'PostSet', @mypostresizefcn);

    and MATLAB accepted this without error, but actually ignored it – evidently since Position is not observable. (MATLAB should at least give me an error to tell me that my listener is not acceptable.)

    Thanks,
    John

    • Yair Altman September 10, 2014 at 10:17 Reply

      @John – I do not know of a way to listen to non-observable properties. Perhaps there is a way, but I don’t know it.

    • Erik May 4, 2015 at 11:58 Reply

      @John – Not the most elegant solution – but you could try to listen for an Event that always executes when position is changed. Using Matlab 2015a; for example, to determine potential event names for an axes position change:

      hAxes = axes;
      md = ?matlab.graphics.axis.Axes;
      eventNames = {md.EventList.Name};
      for iEvent = 1:numel(eventNames)
          addlistener(hAxes, eventNames{iEvent}, @(~,~) disp(eventNames{iEvent}));
      end

      hAxes = axes; md = ?matlab.graphics.axis.Axes; eventNames = {md.EventList.Name}; for iEvent = 1:numel(eventNames) addlistener(hAxes, eventNames{iEvent}, @(~,~) disp(eventNames{iEvent})); end

      And then change your axes position in various manners to see what Events occur. My very-quick testing indicates Events {‘MarkedDirty’, ‘LocationChanged’, ‘SizeChanged’, ‘MarkedClean’} are called in that order.

      Keep in mind some Events {‘MarkedDirty’, ‘MarkedClean’} are called for all sorts of (non-position related) reasons.

    • Julian April 11, 2016 at 10:31 Reply

      Hi John,

      you can listen to a ‘SizeChanged’ Property in HG2 handling

      h = addlistener(gcf,'SizeChanged',@func);

      h = addlistener(gcf,'SizeChanged',@func);

  3. Collin Pecora September 24, 2016 at 00:58 Reply

    Is there a way to listen for property changes of ‘pure’ java objects created in matlab?

    Specificaly, I would like to listen to the value property of a jFormattedTextField as suggested by the javadocs

  4. Ofer Saferman October 24, 2018 at 12:58 Reply

    How do you know which properties are observable?
    Can you in general listen to your own added properties using setappdata? How to make them observable?
    Thanks

    • Yair Altman October 24, 2018 at 13:30 Reply

      @Ofer – you need to set the GetObservable meta-attribute to enable listening to PreGet/PostGet events, and similarly set SetObservable for PreSet/PostSet events. For example:

      hObj = gcf;  % current figure (can be any handle)
      hProp = addprop(hObj,'Yair');
      hProp.SetObservable = true;
      addlistener(hObj,'Yair','PostSet',@(h,e)disp(123));
      hObj.Yair = 2;  % "123" will be displayed in the Matlab console

      hObj = gcf; % current figure (can be any handle) hProp = addprop(hObj,'Yair'); hProp.SetObservable = true; addlistener(hObj,'Yair','PostSet',@(h,e)disp(123)); hObj.Yair = 2; % "123" will be displayed in the Matlab console

      If you forget to set the GetObservable/SetObservable meta-attribute, you will receive a run-time error when you try to call addlistener:

      Error using matlab.ui.Figure/addlistener
      While adding a PostSet listener, property 'Yair' in class 'matlab.ui.Figure' is not defined to be SetObservable.

      Error using matlab.ui.Figure/addlistener While adding a PostSet listener, property 'Yair' in class 'matlab.ui.Figure' is not defined to be SetObservable.

  5. rohit January 29, 2019 at 09:07 Reply

    Yair,

    Can we attach a listener to “text” uicontrol ? So that whenever “String” property of “text” control changes, we can detect it ?

    • Yair Altman January 29, 2019 at 12:37 Reply

      @Rohit – yes you can, but I have no idea why you’d want to do this. After all, text controls are typically changed programmatically (not interactively) so you can call your requested functionality whenever you modify the text.

      In any case, here’s how you can attach the requested callback:

      hText = uicontrol('Style','text', ...);
      hProp = findprop(hText,'String');
      callback = @(h,e) disp(hText.String);  % your callback function handle
      hListener = addlistener(hText, hProp, 'PostSet', callback);

      hText = uicontrol('Style','text', ...); hProp = findprop(hText,'String'); callback = @(h,e) disp(hText.String); % your callback function handle hListener = addlistener(hText, hProp, 'PostSet', callback);

  6. Rohit January 29, 2019 at 13:56 Reply

    @Yair,
    The reason to attach a listener is that, we have a Matlab tool in which “Text control” is written programmatically at 1000’s places. Now, I have introduced a “Message Log Panel” in which I want to put the same messages that were written to “Text control”. Either I go to 1000’s places and place my code to write messages to “Log Panel” or attach a listener to “text control” such that whenever any messages is written to “text control”, it automatically comes to the “Log panel” as well.

    BTW, thanks , your suggestion worked..!

Leave a Reply
HTML tags such as <b> or <i> are accepted.
Wrap code fragments inside <pre lang="matlab"> tags, like this:
<pre lang="matlab">
a = magic(3);
disp(sum(a))
</pre>
I reserve the right to edit/delete comments (read the site policies).
Not all comments will be answered. You can always email me (altmany at gmail) for private consulting.

Click here to cancel reply.

Useful links
  •  Email Yair Altman
  •  Subscribe to new posts (email)
  •  Subscribe to new posts (feed)
  •  Subscribe to new posts (reader)
  •  Subscribe to comments (feed)
 
Accelerating MATLAB Performance book
Recent Posts

Speeding-up builtin Matlab functions – part 3

Improving graphics interactivity

Interesting Matlab puzzle – analysis

Interesting Matlab puzzle

Undocumented plot marker types

Matlab toolstrip – part 9 (popup figures)

Matlab toolstrip – part 8 (galleries)

Matlab toolstrip – part 7 (selection controls)

Matlab toolstrip – part 6 (complex controls)

Matlab toolstrip – part 5 (icons)

Matlab toolstrip – part 4 (control customization)

Reverting axes controls in figure toolbar

Matlab toolstrip – part 3 (basic customization)

Matlab toolstrip – part 2 (ToolGroup App)

Matlab toolstrip – part 1

Categories
  • Desktop (45)
  • Figure window (59)
  • Guest bloggers (65)
  • GUI (165)
  • Handle graphics (84)
  • Hidden property (42)
  • Icons (15)
  • Java (174)
  • Listeners (22)
  • Memory (16)
  • Mex (13)
  • Presumed future risk (394)
    • High risk of breaking in future versions (100)
    • Low risk of breaking in future versions (160)
    • Medium risk of breaking in future versions (136)
  • Public presentation (6)
  • Semi-documented feature (10)
  • Semi-documented function (35)
  • Stock Matlab function (140)
  • Toolbox (10)
  • UI controls (52)
  • Uncategorized (13)
  • Undocumented feature (217)
  • Undocumented function (37)
Tags
ActiveX (6) AppDesigner (9) Callbacks (31) Compiler (10) Desktop (38) Donn Shull (10) Editor (8) Figure (19) FindJObj (27) GUI (141) GUIDE (8) Handle graphics (78) HG2 (34) Hidden property (51) HTML (26) Icons (9) Internal component (39) Java (178) JavaFrame (20) JIDE (19) JMI (8) Listener (17) Malcolm Lidierth (8) MCOS (11) Memory (13) Menubar (9) Mex (14) Optical illusion (11) Performance (78) Profiler (9) Pure Matlab (187) schema (7) schema.class (8) schema.prop (18) Semi-documented feature (6) Semi-documented function (33) Toolbar (14) Toolstrip (13) uicontrol (37) uifigure (8) UIInspect (12) uitools (20) Undocumented feature (187) Undocumented function (37) Undocumented property (20)
Recent Comments
  • Yair Altman (13 days 12 hours ago): @Veronica – you are using the new version of uitree, which uses HTML-based uifigures, and my post was about the Java-based uitree which uses legacy Matlab figures. For...
  • Veronica Taurino (13 days 12 hours ago): >> [txt1,txt2] ans = ‘abrakadabra’
  • Veronica Taurino (13 days 13 hours ago): Hello, I am just trying to change the uitree node name as you suggested: txt1 = 'abra'; txt2 = 'kadabra'; node.setName([txt1,txt2]); >> "Unrecognized method, property, or...
  • Yair Altman (16 days 12 hours ago): The version of JGraph that you downloaded uses a newer version of Java (11) than the one that Matlab supports (8). You need to either (1) find an earlier version of JGraph that...
  • mrv (16 days 17 hours ago): hello, I used MATLAB 2019b update9, I have add jgraphx.jar to javaclassapth, and restart matlab, but still got errors below: Warning: A Java exception occurred trying to load the...
  • xuejie wu (40 days 13 hours ago): Hi: I’m wondering if i can add my customized section or tab ?
  • Yair Altman (52 days 5 hours ago): @Sagar – use the view(az,el) function to rotate the 3D axes.
  • Sagar Chawla (52 days 5 hours ago): I want to know how to change the x-axis to the z-axis. I mean the position. Like if there is a 3d animated graph then how to change position of the axis. X-axis in place of...
  • Ren (52 days 5 hours ago): I noticed that xlsread will create a hidden and never-dying special server that always has priority when actxGetRunningServer is called. So this cause a problem that no matter how many...
  • Ben Abbott (55 days 20 hours ago): Thanks Yair, it was the second. I didn’t not include the drawnow ()
  • Yair Altman (55 days 23 hours ago): @Ben – it looks perfectly ok (with color gradient and all) on my R2022a… Perhaps you missed some of the steps (e.g. setting the ColorBinding to 'interpolated') or...
  • Ben Abbott (55 days 23 hours ago): The graded color is not working for me using R2021a. The plot “HG2 plot line color, transparency gradient” looks exactly like “Transparent HG2 plot...
  • Yair Altman (79 days 2 hours ago): Oliver – you probably forgot to update hMarkers.FaceColorType to ‘truecoloralpha‘: x=1:10; y=10*x; figure; hLine = plot(x,y,'o-'); drawnow...
  • Oliver (79 days 2 hours ago): This seems to have been disabled in the most recent version of Matlab (R2021b). When I use this method the hMarker.FaceColorData does change, but the markers are not made...
  • Yair Altman (98 days 0 hours ago): @Tim – the new uidatepicker() function only works with web-based figures (created using the uifigure() function or App Designer); it is not available on the legacy...
Contact us
Undocumented Matlab © 2009 - Yair Altman
This website and Octahedron Ltd. are not affiliated with The MathWorks Inc.; MATLAB® is a registered trademark of The MathWorks Inc.
Scroll to top