- Undocumented Matlab - https://undocumentedmatlab.com -

Adding dynamic properties to graphic handles

Posted By Yair Altman On September 16, 2015 | 4 Comments

A client recently asked me to extend one of Matlab’s built-in graphic containers (uiflowcontainer [1] in this specific case) with automatic scrollbars that would enable the container to act as a scroll-panel. The basic idea would be to dynamically monitor the container’s contents and when it is determined that they overflow the container’s boundaries, then attach horizontal/vertical scrollbars to enable scrolling the contents into view:

Scrollable Matlab container
Scrollable Matlab container

This may sound simple, but there are actually quite a few undocumented hacks that make this possible, including listening to ObjectChildAdded/ObjectChildRemoved events, location/size/visibility events, layout changes etc. Maybe I’ll blog about it in some future article.
Today’s post is focused on a specific aspect of this project, attaching dynamic properties to the builtin uiflowcontainer, that would enable users to modify the container’s properties directly, as well as control aspects of the scrolling using the new properties: handles to the parent container, as well as the horizontal and vertical scrollbars, and even a new refresh() method.

The “textbook” approach to this would naturally be to create a new class that extends (inherits) uiflowcontainer and includes these new properties and methods. Unfortunately, for some reason that escapes my understanding, MathWorks saw fit to make all of its end-use graphic object classes Sealed, such that they cannot be extended by users. I did ask for this to be changed long ago, but the powers that be apparently decided that it’s better this way.
So the fallback would be to create our own dedicated class having all the new properties as well as those of the original container, and ensure that all the property values are synchronized in both directions. This is probably achievable, if you have a spare few days and a masochistic state of mind. Being the lazy bum and authority-rebel that I am, I decided to take an alternate approach that would simply add my new properties to the built-in container handle. The secret lies in the undocumented function schema.prop (for HG1, R2014a and older) and the fully-documented addprop function (for HG2, R2014b and newer).
In the examples below I use a panel, but this mechanism works equally well on any Matlab HG object: axes, lines, uicontrols, figures, etc.

HG2 – addprop function

The addprop function is actually a public method of the dynamicprops class. Both the dynamicprops class as well as its addprop function are fully documented [2]. What is NOT documented, as far as I could tell, is that all of Matlab’s builtin handle graphics objects indirectly inherit dynamicprops, via matlab.graphics.Graphics, which is a high-level superclass for all HG objects. The bottom line is that we can dynamically add run-time properties to any HG object, without affecting any other object. In other words, the new properties will only be added to the handles that we specifically request, and not to any others. This suits me just fine:

hProp = addprop(hPanel, 'hHorizontalScrollBar');
hPanel.hHorizontalScrollBar = hMyScrollbar;
hProp.SetAccess = 'private';  % make this property read-only

The new property hHorizontalScrollBar is now added to the hPanel handle, and can be accessed just like any other read-only property. For example:

>> get(hPanel, 'hHorizontalScrollBar')
ans =
    JavaWrapper
>> hPanel.hHorizontalScrollBar
ans =
    JavaWrapper
>> hPanel.hHorizontalScrollBar = 123
You cannot set the read-only property 'hHorizontalScrollBar' of UIFlowContainer.

Adding new methods is more tricky, since we do not have a corresponding addmethod function. The trick I used was to create a new property having the requested new method’s name, and set its read-only value to a handle of the requested function. For example:

hProp = addprop(hPanel, 'refresh');
hPanel.refresh = @myRefreshFunc;
hProp.SetAccess = 'private';  % make this property read-only

We can then invoke the new refresh “method” using the familiar dot-notation:

hPanel.refresh();

Note: if you ever need to modify the initial value in your code, you should revert the property’s SetAccess meta-property to 'public' before Matlab will enable you to modify the value:

try
    % This will raise an exception if the property already exists
    hProp = addprop(hPanel, propName);
catch
    % Property already exists - find it and set its access to public
    hProp = findprop(hPanel, propName);
    hProp.SetAccess = 'public';
end
hPanel.(propName) = newValue;

HG1 – schema.prop function

In HG1 (R2014a and earlier), we can use the undocumented schema.prop function to add a new property to any HG handle (which is a numeric value in HG1). Donn Shull wrote about schema.prop [3] back in 2011, as part of his series of articles on UDD (Unified Data Dictionary, MCOS’s precursor). In fact, schema.prop is so useful that it has its own blog tag here [4] and appears in no less than 15 separate articles (excluding today). With HG2’s debut 2 years ago, MathWorks tried very hard to rid the Matlab code corpus of all the legacy schema-based, replacing most major functionalities with MCOS-based HG2 code. But so far it has proven impossible to get rid of schema completely, and so schema code is still used extensively in Matlab to this day (R2015b). Search your Matlab path for “schema.prop” and see for yourself.
Anyway, the basic syntax is this:

hProp = schema.prop(hPanel, propName, 'mxArray');

The 'mxArray' specifies that the new property can accept any data type. We can limit the property to only accept certain types of data by specifying a less-generic data type, among those recognized by UDD (details [5]).
Note that the meta-properties of the returned hProp are somewhat different from those of HG2’s hProp. Taking this into account, here is a unified function that adds/updates a new property (with optional initial value) to any HG1/HG2 object:

function addProp(hObject, propName, initialValue, isReadOnly)
    try
        hProp = addprop(hObject, propName);  % HG2
    catch
        try
            hProp = schema.prop(hObject, propName, 'mxArray');  % HG1
        catch
            hProp = findprop(hObject, propName);
        end
    end
    if nargin > 2
        try
            hProp.SetAccess = 'public';  % HG2
        catch
            hProp.AccessFlags.PublicSet = 'on';  % HG1
        end
        hObject.(propName) = initialValue;
    end
    if nargin > 3 && isReadOnly
        try
            % Set the property as read-only
            hProp.SetAccess = 'private';  % HG2
        catch
            hProp.AccessFlags.PublicSet = 'off';  % HG1
        end
    end
end

Categories: GUI, Handle graphics, High risk of breaking in future versions, Stock Matlab function, UI controls, Undocumented feature, Undocumented function


4 Comments (Open | Close)

4 Comments To "Adding dynamic properties to graphic handles"

#1 Comment By Yaroslav On September 17, 2015 @ 02:41

This is probably achievable, if you have a spare few days and a masochistic state of mind.” — Laughed my head off about that one. Recalling the onerous days required to rewrite the [12] [13], I couldn’t agree more.

Supporting @Yair’s point of view, I also find the sealing of HG classes vexing. Although the dynamicprops approach may suit small programs or ad hoc solutions, it’s not applicable for large projects or general cases. IMHO, a proper inheritance is invaluable in this matter. Perhaps we could write a petition to TMW and ask for the seal to be broken?

#2 Comment By Julien On September 24, 2015 @ 13:13

Very interesting… But when I see your first figure with this scrollable container which contains an axes, I would like to know more! Could you briefly explain how you succeedded in adding a scrollbar to the flowcontainer? Thanks in advance!

#3 Comment By Will On November 12, 2015 @ 10:59

If you’re just storing something like a handle and don’t have any use for OOP concepts like access attributes or property listeners, is there any particular advantage to using dynamic properties rather than setappdata and getappdata? It seems to me the only disadvantage of application data for this purpose is the slightly less concise means of access – but in exchange for being able to assign in one line rather than two. Is there anything else worth considering?

#4 Comment By Andrew Joslin On February 17, 2016 @ 20:41

To extend @Yair’s implementation a little bit…

1) You can overload a builtin function or sealed class (like axes), and in the overloaded function define some dynamic properties
2) To add dynamic “methods” which don’t require empty parentheses when called, take @Yair’s implementation and then also define the “GetMethod” parameter of that dynamic property to be the same function handle that you set the property to.

I’m still learning OOP, and am very new to design patterns, but perhaps this is how to implement a decorator pattern in MATLAB, given that sealed classes cannot be subclassed?

function ax = axes(varargin)

   % Create a builtin axes object
   ax = builtin('axes',varargin{:});

   % Add a dynamic method
   p = addprop(ax,'newmethod');
   ax.newmethod = @(x)fun(ax); % Maybe there's a better way to pass the axes to an anonymous function?
   p.GetMethod = @(x)fun(ax);
   p.SetAccess = 'private';

   function out = fun(ax)
      % Do stuff here
   end
end

Now you can call the dynamic “method”, newmethod, without using parentheses, and the object is passed to newmethod when called, just as in a normal class method:

a = axes;
a.newmethod;

Article printed from Undocumented Matlab: https://undocumentedmatlab.com

URL to article: https://undocumentedmatlab.com/articles/adding-dynamic-properties-to-graphic-handles

URLs in this post:

[1] uiflowcontainer: http://undocumentedmatlab.com/blog/matlab-layout-managers-uicontainer-and-relatives

[2] fully documented: http://www.mathworks.com/help/matlab/ref/dynamicprops.addprop.html

[3] wrote about schema.prop: http://undocumentedmatlab.com/blog/udd-properties

[4] blog tag here: http://undocumentedmatlab.com/blog/tag/schemaprop

[5] details: http://undocumentedmatlab.com/blog/udd-properties#DataType

[6] Adding custom properties to GUI objects : https://undocumentedmatlab.com/articles/adding-custom-properties-to-gui-objects

[7] Performance: accessing handle properties : https://undocumentedmatlab.com/articles/performance-accessing-handle-properties

[8] Graphic sizing in Matlab R2015b : https://undocumentedmatlab.com/articles/graphic-sizing-in-matlab-r2015b

[9] UDD Properties : https://undocumentedmatlab.com/articles/udd-properties

[10] getundoc – get undocumented object properties : https://undocumentedmatlab.com/articles/getundoc-get-undocumented-object-properties

[11] Accessing private object properties : https://undocumentedmatlab.com/articles/accessing-private-object-properties

[12] : https://undocumentedmatlab.com/blog/undocumented-cursorbar-object

[13] : http://www.mathworks.com/matlabcentral/fileexchange/49612-cursorbar

Copyright © Yair Altman - Undocumented Matlab. All rights reserved.