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 (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
  • Marcel (9 days 13 hours ago): Hi, I am trying to set the legend to Static, but this command seems not to work in R2022a anymore: set(gca,’LegendColorbarL isteners’,[]); Any ideas? THANKS / marcel
  • Gres (9 days 17 hours ago): In 2018b, you can get the icons by calling [hh,icons,plots,txt] = legend({‘Line 1’});
  • Yair Altman (11 days 11 hours ago): @Mitchell – in most cases the user wants a single string identifier for the computer, that uniquely identifies it with a distinct fingerprint that is different from any...
  • Mitchell (11 days 20 hours ago): Great post! I’m not very familiar with the network interfaces being referenced here, but it seems like the java-based cross-platform method concatenates all network...
  • Yair Altman (14 days 14 hours ago): Dani – You can use jViewport.setViewPosition(java .awt.Point(0,0)) as I showed in earlier comments here
  • dani (15 days 9 hours ago): hi!! how i can set the horizontal scrollbar to the leftside when appearing! now it set to right side of text
  • Yair Altman (24 days 6 hours ago): Dom – call drawnow *just before* you set hLine.MarkerHandle.FaceColorTy pe to 'truecoloralpha'. Also, you made a typo in your code: it’s truecoloralpha, not...
  • Dom (25 days 4 hours ago): Yair I have tried your code with trucoloralpha and the markers do not appear transparent in R2021b, same as for Oliver.
  • Yair Altman (28 days 12 hours ago): Ren – This is usually the expected behavior, which avoids unnecessary duplications of the Excel process in CPU/memory. If you want to kill the process you can always run...
  • Yair Altman (29 days 2 hours ago): When you use plot() without hold(‘on’), each new plot() clears the axes and draws a new line, so your second plot() of p2 caused the first plot() line (p1) to be...
  • Cesim Dumlu (35 days 9 hours ago): Hello. I am trying to do a gradient plot for multiple functions to be displayed on the same axes and each one is colorcoded by respective colordata, using the same scaling. The...
  • Yair Altman (43 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 (43 days 12 hours ago): >> [txt1,txt2] ans = ‘abrakadabra’
  • Veronica Taurino (43 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 (46 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...
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