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

Adding dynamic properties to graphic handles

September 16, 2015 4 Comments

A client recently asked me to extend one of Matlab’s built-in graphic containers (uiflowcontainer 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. 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

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

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

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;

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 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 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');

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).
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

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

Related posts:

  1. Adding custom properties to GUI objects – It is very easy to add custom user-defined properties and methods to GUI handles and Java references in Matlab. ...
  2. Performance: accessing handle properties – Handle object property access (get/set) performance can be significantly improved using dot-notation. ...
  3. Graphic sizing in Matlab R2015b – Matlab release R2015b's new "DPI-aware" nature broke some important functionality. Here's what can be done... ...
  4. UDD Properties – UDD provides a very convenient way to add customizable properties to existing Matlab object handles...
  5. getundoc – get undocumented object properties – getundoc is a very simple utility that displays the hidden (undocumented) properties of a specified handle object....
  6. Accessing private object properties – Private properties of Matlab class objects can be accessed (read and write) using some undocumented techniques. ...
Donn Shull Handle graphics HG2 Pure Matlab schema.prop Undocumented feature Undocumented function
Print Print
« Previous
Next »
4 Responses
  1. Yaroslav September 17, 2015 at 02:41 Reply

    “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 graphics.cursorbar object into its HG2 counterpart, 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. Julien September 24, 2015 at 13:13 Reply

    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. Will November 12, 2015 at 10:59 Reply

    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. Andrew Joslin February 17, 2016 at 20:41 Reply

    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

    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;

    a = axes; a.newmethod;

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 (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
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) uitable (6) uitools (20) Undocumented feature (187) Undocumented function (37) Undocumented property (20)
Recent Comments
Contact us
Captcha image for Custom Contact Forms plugin. You must type the numbers shown in the image
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