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

Adding custom properties to GUI objects

Posted By Yair Altman On February 15, 2018 | 6 Comments

Matlab objects have numerous built-in properties (some of them publicly-accessible/documented and others not, but that’s a different story). For various purposes, it is sometimes useful to attach custom user-defined properties to such objects. While there was never a fully-documented way to do this, most users simply attached such properties as fields in the UserData property or the object’s [hidden] ApplicationData property (accessible via the documented setappdata/getappdata functions).
An undocumented way to attach actual new user-defined properties to objects such as GUI handles or Java references has historically (in HG1, up to R2014a) been to use the undocumented schema.prop function, as I explained here [1]. As I wrote in that post, in HG2 (R2014b onward), we can use the fully-documented addprop function [2] to add new custom properties (and methods) to such objects. What is still NOT documented, as far as I could tell, is that all of Matlab’s builtin handle graphics objects indirectly inherit the dynamicprops class, which allows this. The bottom line is that we can dynamically add custom properties in run-time 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.
All this is important, because for some unexplained reason that escapes my understanding, MathWorks chose to seal its classes, thus preventing users to extend them with sub-classes that contain the new properties. So much frustration could have been solved if MathWorks would simply remove the Sealed class meta-property from its classes. Then again, I’d have less to blog about in that case…
Anyway, why am I rehashing old news that I have already reported a few years ago?
Well, first, because my experience has been that this little tidbit is [still] fairly unknown by Matlab developers. Secondly, I happened to run into a perfect usage example a short while ago that called for this solution: a StackExchange user asked [3] whether it is possible to tell a GUI figure’s age, in other words the elapsed time since the figure was created. The simple answer would be to use setappdata with the creation date whenever we create a figure. However, a “cleaner” approach seems to be to create new read-only properties for the figure’s CreationTime and Age:

First, create a small Matlab function as follows, that attaches the CreationTime property to a figure:

function setCreationTime(hFig,varargin)
   hProp = addprop(hFig,'CreationTime');
   hFig.CreationTime = now;
   hProp.SetAccess = 'private';  % make property read-only after setting its initial value
   hProp = addprop(hFig,'Age');
   hProp.GetMethod = @(h,e) etime(datevec(hFig.CreationTime), clock);  % compute on-the-fly
   hProp.SetAccess = 'private';  % make property read-only
end

Now assign this function as the default CreateFcn callback function for all new figures from now on:

set(0,'DefaultFigureCreateFcn',@setCreationTime)

That’s it – you’re done! Whenever a new figure will be created from now on, it will have two custom read-only properties: CreationTime and Age.
For example:

>> newFig = figure;
>> newFig.CreationTime
ans =
      737096.613706748
>> ageInDays = now - newFig.CreationTime
ageInDays =
       0.0162507836846635
>> ageDuration = duration(ageInDays*24,0,0)
ageDuration =
  duration
   00:23:24
>> ageString = datestr(ageInDays, 'HH:MM:SS.FFF')
ageString =
    '00:23:24.068'
>> ageInSecs = newFig.Age
ageInSecs =
       1404.06771035492

Note that an alternative way to set the computed property Age would have been to set its value to be an anonymous function, but this would have necessitated invoking it with parenthesis (as in: ageInSecs = newFig.Age()). By setting the property’s GetMethod meta-property we avoid this need.
Keen readers will have noticed that the mechanism that I outlined above for the Age property/method can also be used to add custom user methods. For example, we can create a new custom property named refresh that would be read-only and have a GetMethod which is the function handle of the function that refreshes the object in some way.
Do you have any special uses for custom user-defined properties/methods in your program? or perhaps you have a use-case that might show MathWorks why sub-classing the built-in classes might improve your work? if so, then please place a comment about it below. If enough users show MathWorks why this is important, then maybe it will be fixed in some future release.

Categories: GUI, Handle graphics, Java, Low risk of breaking in future versions, Undocumented feature


6 Comments (Open | Close)

6 Comments To "Adding custom properties to GUI objects"

#1 Comment By Yaroslav On February 19, 2018 @ 23:36

Hi Yair,

Kudos for bringing up this Sealed issue; I couldn’t have agreed with you more. It is indeed a perplexing decision that hampers one’s work.

I have first encountered this problem while updating the [10] to the new [11]. Since Cursorbar needed — on top of a plethora of new properties — events and methods with arguments, and since it had to be “real time,” the simple solution of addprop just wouldn’t suffice. It would have been much easier to subclass either Group or some other handle graphics class; alas, being not the case, I had to wiggle myself around to keep the desired behavior and compatibility with handle graphics. As you can imagine, it came with some cost, and some things still don’t work properly as a result.

I believe the Matlab community should press strongly on this matter. Maybe, a shared “new functionality” request between many people or a petition of some sort will do the trick. In any case, it would help to hear a clarification from Mathworks about this decision; perhaps, they have some reasons we’re unaware of.

Cheers and keep up the good work.

#2 Comment By Jan On March 21, 2018 @ 11:03

I agree on pushing on that sealing issue. What can we do? It would be great to subclass some graphics elements.

#3 Comment By Eric Sargent On March 5, 2018 @ 20:59

Hello Yair,
Thank you for your comments about how unsealing classes would be beneficial for you and other users.
At present, we have not unsealed these because doing so could limit our ability to change the implementation strategy in future releases. That being said, we have heard this request in the graphics area as well (not just UI) and we are researching how this might be possible in the future. To help us in doing this, would you be willing to share additional specific use cases that you’re thinking about? If so, please send me an email with your thoughts and I will share with the development teams, as I’m sure they would love to hear your input.
Thank you!
Eric Sargent
Product Manager at The MathWorks

#4 Comment By Yair Altman On March 13, 2018 @ 11:23

@Eric – I really appreciate the fact that you took the time to post your comment and state MathWorks’ position on this matter publicly. This is not taken for granted at all.

However, I have to tell you that I find your reasoning for sealing Matlab classes perplexing to say the least. Please correct me if I’m mistaken, but I believe that Java, C++, C# and VB.Net — to name just a few well-known object-oriented programming languages/environments, all of which have far greater following than Matlab — have not seen fit to seal their classes in the general case (GUI/graphics included), and I do not think that this has ever hampered their growth. The same can be said for many if not all of the numerous commercial and open-source libraries that MathWorks uses within Matlab.

Any user who extends a built-in class, in *any* programming language, knows full-well that this might break in the future. This is still much better than not being able to accomplished the requested functionality today. Such users might tell themselves that since the other platforms are not as limiting, it might make sense to drop Matlab in their favor.

Limiting users’ ability to use Matlab today, under the vague notion that this might possibly make life a bit harder for MathWorks developers one day in the far future, is IMHO plain nearsightedness. On the contrary – let the user community extend the built-in Matlab classes, and then you could incorporate the best of these extensions in future Matlab releases (at no expense to MathWorks!). Just my personal ¢2, please don’t kill the messenger…

#5 Comment By Michelle Hirsch On March 15, 2018 @ 22:23

Yair,
Thanks as always for openly sharing your two cents – always worth way more than just a few pennies!

I totally understand where you are coming from – the benefits to users of subclassing are clear, as you’ve articulated. That said, I still believe we need to proceed very carefully if we intentionally open up parts of MATLAB that we aren’t committed to keeping as compatible as possible over time. You refer to the risk as “potentially making life a bit harder for MathWorks developers one day”. I see it very differently – I see the primary risk to our users, not MathWorks developers. Our developers evolve the product to meet demand from our users; constraints on changing underlying implementation and architecture can significantly hinder our ability to keep up with user demands. Of course, nothing is black-and-white – you know better than almost anybody about the trade-off between getting capabilities now and code potentially breaking in the future.

I’m intrigued by your notion that developers have a different expectation of compatibility when subclassing than they might have when calling documented programing interfaces directly. I’ve long been interested in figuring out “safe” ways for us to give advanced users more flexibility while still managing release compatibility expectations, so maybe this points in a fruitful direction. I could imagine a world where we set expectations that subclassing is not guaranteed to work in the future. I can see this working in a direct conversation with the developers who subclass, but I really worry about the downstream user who relies on this subclassed code who doesn’t know why their code broke with a new release, has no idea how to fix it and potentially no ability to get the author to fix it, either. This reflects the nature of how a majority of MATLAB code spreads in the wild today.

As always, I encourage other readers to jump in with their perspectives. Yair and I could discuss more next time we meet.

#6 Comment By Jan Kappen On May 20, 2020 @ 15:49

@Eric, I’m just curious, is the new chart container class ( [12]) the approach you mentioned?

Thanks.


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

URL to article: https://undocumentedmatlab.com/articles/adding-custom-properties-to-gui-objects

URLs in this post:

[1] explained here: http://undocumentedmatlab.com/blog/adding-dynamic-properties-to-graphic-handles

[2] addprop function: https://www.mathworks.com/help/matlab/ref/dynamicprops.addprop.html

[3] StackExchange user asked: https://stackoverflow.com/questions/48597836/matlab-figure-age

[4] Adding dynamic properties to graphic handles : https://undocumentedmatlab.com/articles/adding-dynamic-properties-to-graphic-handles

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

[6] Borderless button used for plot properties : https://undocumentedmatlab.com/articles/borderless-button-used-for-plot-properties

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

[8] Adding a search box to figure toolbar : https://undocumentedmatlab.com/articles/adding-a-search-box-to-figure-toolbar

[9] Plot LimInclude properties : https://undocumentedmatlab.com/articles/plot-liminclude-properties

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

[11] : https://www.mathworks.com/matlabcentral/fileexchange/49612-cursorbar

[12] : https://de.mathworks.com/help/matlab/ref/matlab.graphics.chartcontainer.chartcontainer-class.html

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