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);
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);
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
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);
(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!
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.