One of my many File Exchange submissions, UISplitPane, was chosen yesterday as Matlab Central’s Pick of the Week (thanks Jiro!). UISplitPane was probably my most challenging submission to date. I thought it would be a good point in time to share some of the undocumented features that I used in UISplitPane. Readers are encouraged to download UISplitPane.m and look at its code.
The basic problem which UISplitPane solves is the inability in Matlab to construct a dual pane separated by an interactive divider. Such split-panes are very common in modern GUIs, including Matlab tools, but were never available for Matlab GUIs. Java Swing has the JSplitPane control, but Matlab axes cannot (as yet) be added to Java containers. A similar problem exists for tabbed-panes, and Matlab provided a very innovative solution for this (the semi-documented uitabgroup function), which is described in a separate post. Unfortunately, uitabgroup‘s solution cannot be applied to the split-pane problem since in JSplitPane’s case, the container overlaps the axes-containing panes.
To make a long story short, the solution was to create an off-screen (invisible) JSplitPane, extract only its narrow central divider sub-component, and place that onscreen using javacomponent. I encourage readers to look at the addDivider() function which does this, setting mouse cursor and other interesting properties.
The Java divider’s reference is then converted into a Matlab handle, so that some extra properties can be added using schema.prop (which [you guessed it] will be described in a later post) and will become visible when using regular get.
Pure-Matlab code then attaches standard Matlab uipanels as sub-panes on either side of the divider. Property linkages (this will be detailed in later posts about schema.prop’s getter/setter functions and handle.listener) ensure that whenever the divider is dragged or programmatically modified, the two sub-panes on its sides will be resized accordingly, together with all their content (axes and controls). Since the two split panes are simple uipanels, they can contain not only axes and controls but also other uisplitpanes, creating a hierarchy of split-panes:
[hDown,hUp,hDiv1] = uisplitpane(gcf, 'Orientation','ver', 'dividercolor',[0,1,0]); [hLeft,hRight,hDiv2] = uisplitpane(hDown, 'dividercolor','r', 'dividerwidth',3); t=0:.1:10; hax1=axes('Parent',hUp); plot(t,sin(t)); hax2=axes('parent',hLeft); plot(t,cos(t)); hax3=axes('parent',hRight); plot(t,tan(t)); hDiv1.DividerLocation = 0.75; % one way to modify divider properties... set(hDiv2,'DividerColor','red'); % ...and this is another way...
UISplitPane makes use of some semi-documented internal helper functions: hgfeval is used in the mouse callbacks, in order to chain the original WindowButton callback (if available); setptr is used to set the mouse pointer (cursor).
UISplitPane behaves nicely in the presence of Mode Managers (zoom, pan, …) by using the figure’s undocumented ‘ModeManager’ property and setting its ‘ButtonDownFilter’ to bypass mode.
Finally, the figure’s undocumented ‘JavaFrame’ property is used to get a reference to the figure’s AxisComponent container, which is needed for setting mouse callbacks that behave better than similar callbacks at the figure level.
All-in-all, UISplitPane is perhaps a good example of combining a variety of unrelated undocumented Matlab features in order to achieve a coherent application.
An interesting side-note: Matlab 7.6 (R2008a) and onward contain a reference to uisplittool and uitogglesplittool in the javacomponent.m and %matlabroot%/bin/registry/hg.xml files. These are not valid functions (built-in or otherwise) and I could not figure out how this functionality can actually be used. At the very least it is certain that it is deeply undocumented and (of course) unsupported, leaving an open mystery for future investigation…
Addendum Jan 14, 2015: For an alternative implementation of split-panes, see here.