A friend recently asked me, in light of my guesstimate that Java-based Matlab figures will be replaced by web-based figures sometime around 2018-2020, whether there are any “killer features” that make it worthwhile to use undocumented Java-based tricks today, despite the fact that they will probably break in 2-5 years. In my opinion, there are many such features; today I will focus on just a subset of them – those features that relate to the entire figure window.
Over the years I wrote many articles here about figure-level customizations, as well as an entire chapter in my Matlab-Java programming book. So today’s post will be a high-level overview, and users who are interested in any specific topic can visit the referenced links for the implementation details.
An undecorated Matlab figure window – one of many possible figure-level customizations
JavaFrame
JavaFrame is an undocumented hidden property of the figure handle that provides access to the underlying Java window (JFrame
) peer object’s reference. Since R2008a, a warning is issued whenever we retrieve this property:
>> jFrame = get(gcf,'JavaFrame'); Warning: figure JavaFrame property will be obsoleted in a future release. For more information see the JavaFrame resource on the MathWorks web site. (Type "warning off MATLAB:HandleGraphics:ObsoletedProperty:JavaFrame" to suppress this warning.)
Until HG2 (R2014b+) we could suppress the warning by simply wrapping the figure handle within a handle() call, as explained here. Since R2014b we need to use the warning function to do this:
warning('off', 'MATLAB:HandleGraphics:ObsoletedProperty:JavaFrame'); |
We can do several things directly with the JavaFrame‘s properties and methods, including:
- Maximize/minimize/restore the window, via the properties Maximized/Minimized (which accept and return a boolean (logical) value), or the corresponding methods jFrame.isMaximized(), isMinimized(), setMaximized(flag), setMinimized(flag). details
- Modify the container to which the figure will be docked. By default this is the “Figures” container, but this can be changed to any user-specified container, or even to the “Editor”, using the GroupName property or its associated methods. See the related setFigDockGroup utility that I posted on the Matlab File exchange.
- Remove the top separator line between the toolbar and the content-pane, to blend them together, via the jFrame.showTopSeparator(flag) method.
- Retrieve a direct Java reference to the Matlab Desktop and the figure’s internal containers via the Desktop and FigurePanelContainer properties, respectively (we can also get those references by other means).
- Retrieve a direct Java reference to the containing
JFrame
(Java window), as discussed below - A few other features that I will not discuss here
MathWorks have set up a dedicated webpage where you can specify how you are using JavaFrame and why it is important for you: http://www.mathworks.com/javaframe. I encourage you to use this webpage to tell MathWorks which features are important for you. This will help them to decide which functionality should be added to the new web-based figures.
JFrame window
The JavaFrame handle enables direct retrieval of the containing Java JFrame
(window) reference, using several alternatives. Here are two of these alternatives (there are others):
% Alternative #1 >> jWindow = jFrame.getFigurePanelContainer.getTopLevelAncestor jWindow = com.mathworks.hg.peer.FigureFrameProxy$FigureFrame[fClientProxyFrame,72,62,576x507,...] % Alternative #2 try jClient = jFrame.fFigureClient; % This works up to R2011a catch try jClient = jFrame.fHG1Client; % This works from R2008b-R2014a catch jClient = jFrame.fHG2Client; % This works from R2014b and up end end jWindow = jClient.getWindow; |
With the retrieved jWindow
reference, we can do several additional interesting things:
- Enable/disable the entire figure in a single go (details)
- Remove/restore the window frame (borders and title bar), otherwise known as an “undecorated window” (details)
- Set the figure window to be “Always-On-Top”, i.e. not occluded by any other window, via the AlwaysOnTop property, or the corresponding jWindow.isAlwaysOnTop(), setAlwaysOnTop(flag) methods.
- Make the figure window fully or partially transparent (details). Note: this fails on R2013b/Java7 and higher due to a change in the way that transparency works in Java 7 compared to earlier releases; in other words blame Oracle’s Java, not MathWorks’ Matlab….
- Blur/restore the figure window (details). This too works only up to R2013a.
- Detect and handle window-level focus gain/loss events (details), as well as window-level mouse events (enter/exit/hover etc. – details).
- Customize the figure’s menu bar – dynamic behavior, tooltips, highlights, keyboard shortcuts/accelerators, font colors/styles, callbacks, icons etc. (details1, details2)
- Control figure docking in compiled (deployed) applications (details1, details2)
- Display an integral figure status-bar with text and GUI controls (details1, details2).
- A few other features that I will not discuss here
As you can see, there are numerous very interesting customizations that can be done to Matlab figures which rely on the undocumented implementation. Here are a couple of usage examples that you can easily adapt (follow the links above for additional details and usage examples):
jWindow.setEnabled(false); % disable entire figure [true/false] jWindow.setMinimized(true); % minimize window [true/false] jWindow.setMaximized(true); % maximize window [true/false] jWindow.setAlwaysOnTop(true); % set to be always on top [true/false] % Set a Matlab callback function to a window focus-gain event hjWindow = handle(jWindow, 'CallbackProperties'); hjWindow.FocusGainedCallback = @myCallbackFunc; |
In addition to the Java-based features above, some functionalities can also be achieved via direct OS manipulations, for example using Jan Simon’s great WindowAPI utility (Windows-only), although I typically prefer using the Java approach since it is cross-platform compatible.
Using all these features is super-easy, so there is not really a question of code complexity or technical risk – the main question is whether to accept the risk that the associated code will stop working when Matlab figures will eventually become web-based.
So is it worth the risk?
This is an excellent question. I contend that the answer depends on the specific use-case. In one project you may decide that it is indeed worth-while to use these undocumented features today, whereas in another GUI you may decide that it is not.
It might make sense to use the features above in any of the following circumstances:
- If you need any of the features in your Matlab GUI today. In this case, you really have no alternative other than to use these features, since there is no documented way to achieve the required functionality.
- If you do not plan to upgrade your Matlab release soon, or at least after the Java-based figures are discontinued in a few years. The commercial Matlab license is perpetual, enabling users to enjoy these features for as long as they continue using this Matlab release.
- If you are compiling your Matlab program using the Matlab Compiler or Coder toolboxes. In such cases, the executable will remain static, until such time (if ever) that you decide to recompile it using a newer Matlab release. Users of the compiled code could continue to use the compiled undocumented features well into the future, for as long as their computers keep running. In such cases, we are not concerned with release compatibility issues.
- If you accept the risk that some recoding may be necessary in the future, or that some functionality will degrade, for the added benefit that they provide your GUIs today.
- If you are willing to code without MathWorks’ official support and endorsement, and accept the fact that they will not fix any internal bugs that you may discover which is related to these features.
- If you wish to present a professional-grade GUI today, and worry about potential incompatibilities only if and when they eventually arrive, sometime in the future.
Here’s another twist to consider: do not take it for granted that when web-based uifigures replace Java-based figures all the documented functionality will work as-is on the new uifigures just as they have on the old figures. In fact, I personally believe that we will need to extensively modify our GUI code to make it compatible with the new uifigures. In other words, avoiding the undocumented hacks above will probably not save us from the need to recode (or at least adapt) our GUI, it will just reduce the necessary work somewhat. We encountered a similar situation with the graphics hacks that I exposed over the years: many people avoided them in the fear that they might someday break; then when R2014b came and HG2 graphics replaced HG1, it turned out that many of these supposedly risky hacks continued working in HG2 (examples: LooseInset, YLimInclude) whereas quite a bit of standard fully-documented Matlab functionality was broken and required some recoding. I believe that the lessons from the HG2 migration were well studied and assimilated by MathWorks, but realistically speaking we should not expect a 100% full-proof transition to uifigures.
Still, accepting the risk does not mean that we should bury our head in the sand. Whenever using any undocumented feature in your code, I strongly suggest to use defensive coding practices, such as wrapping your code within try-catch blocks. This way, even if the feature is removed in R2020a (or whenever), the program will still run, albeit with somewhat diminished functionality, or in other words, graceful degradation. For example:
try jFrame = get(hFig, 'JavaFrame'); jFrame.setMaximized(true); catch oldUnits = get(hFig, 'Units'); set(hFig, 'Units','norm', 'Pos',[0,0,1,1]); set(hFig, 'Units',oldUnits); end |
Once again, I urge you to visit http://www.mathworks.com/javaframe and tell MathWorks which of the above features are important for you. The more users tell MathWorks that they depend on a specific feature, the more would MathWorks be likely to invest R&D efforts in enabling it in the future web-based figures.