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

UISplitPane

March 28, 2009 18 Comments

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

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

Two levels of UISplitPane, with customized dividers
Two levels of UISplitPane, with customized dividers

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.

Related posts:

  1. Unorthodox checkbox usage – There are various ways to display interactive split-panes in Matlab GUI. Uiextras flex-panels override a checkbox control's CData to display a divider. ...
  2. Fixing a Java focus problem – Java components added to Matlab GUIs do not participate in the standard focus cycle - this article explains how to fix this problem....
  3. Common javacomponent problems – The javacomponent function is very useful for placing Java components on-screen, but has a few quirks. ...
  4. Continuous slider callback – Matlab slider uicontrols do not enable a continuous-motion callback by default. This article explains how this can be achieved using undocumented features....
  5. Inactive Control Tooltips & Event Chaining – Inactive Matlab uicontrols cannot normally display their tooltips. This article shows how to do this with a combination of undocumented Matlab and Java hacks....
  6. Setting listbox mouse actions – Matlab listbox uicontrol can be modified to detect mouse events for right-click context menus, dynamic tooltips etc....
GUI Java uicontrol uisplitpane
Print Print
« Previous
Next »
18 Responses
  1. Mikhail April 1, 2009 at 14:22 Reply

    Dear Yair,

    Thank you very much for starting blogging and investing so much effort in gaining and sharing you knowledge!

    About split pane: I think that this component is great for axes and possibly few uicontrols, but would be much more powerfull when embedded into a consistent Layout Manager. What do you think about it?

    It is really valuable to see all undocumented features, but apart from this point why have you opted for such complex implementation? I naively think it could be possible in pure matlab…

    • Yair Altman April 2, 2009 at 03:29 Reply

      @Mikhail – uisplitpane (or the split-panes concept, same as the tab-panes concept) is a component that can be embedded into any Matlab container or Layout Manager (Matlab itself has several layout managers – see the File Exchange), just like any other Matlab component/container. That was an important design point of uisplitpane. I agree that my sample screenshot would be more powerful if I showed the split-panes embedded in some Matlab uipanel – If I have some spare time I’ll do this.

      Using the Java divider (as opposed to pure-Matlab button) enabled me to use its internal one-click flush hotspots (the arrows near the top/left end of the dividers that enable to flush the divider all the way to the side in one click) with a special mouse hover cursor. The property listeners were required to ensure that whenever the divider was modified, the split-panes did as well – this cannot be done in pure Matlab. The other undocumented functions had their own special reasons too.

  2. wei April 2, 2009 at 06:41 Reply

    Yair, This is nice. How easy to implement a round slider, like a meter?

    • Yair Altman April 2, 2009 at 07:02 Reply

      Wei – the standard javax.swing.JSlider doesn’t have this out-of-the-box, but you can easily integrate 3rd-party components that do this. Google is your best friend, or search one of numerous Swing component repositories, like http://swing-components.safe-install.com/

  3. Anonymous May 15, 2009 at 04:17 Reply

    This will solve the problems people have with R2008b and latter (exceptions…)

    This also solve the exceptions with your brilliant Systray software.

    Regards

    t=java.awt.Toolkit.getDefaultToolkit()
    ev=t.getAWTEventListeners()
    for i=1:length(ev)
        str=ev(i).getListener().getClass.toString
        if str.indexOf('com.mathworks.mwswing.desk.DTSelectionManager')>=0 || ...
           str.indexOf('javax.swing.plaf.basic.BasicLookAndFeel')>=0
            t.removeAWTEventListener(ev(i))
        end
    end

    t=java.awt.Toolkit.getDefaultToolkit() ev=t.getAWTEventListeners() for i=1:length(ev) str=ev(i).getListener().getClass.toString if str.indexOf('com.mathworks.mwswing.desk.DTSelectionManager')>=0 || ... str.indexOf('javax.swing.plaf.basic.BasicLookAndFeel')>=0 t.removeAWTEventListener(ev(i)) end end

    • Yair Altman May 15, 2009 at 04:21 Reply

      Thanks J 🙂

    • Alexander May 4, 2012 at 01:09 Reply

      Dear Yair, dear Anonymus,

      while trying to implement my own code to use a systray icon (Yair, your systray function is great but throws many warnings about “depreciated use of set/get” in more recent Matlab versions), I stumbled over another error message using the java code.
      Though above code resolves the issue in Matlab 2010b, in 2011b, the issued event is com.mathworks.widgets.desk.DTDocumentBar.wantsToHandle

      So you should add this to your list.

      By the way: Which events are triggered by these four (to be removed) event_listeners and why could they easily be removed without changing other stuff?

      The code I used is basically:

      systray_icon = rand(16,16,3);
      trayimage = im2java(systray_icon);
      handles.java.TrayIcon = java.awt.TrayIcon(trayimage);
      java.awt.SystemTray.getSystemTray.add(handles.java.TrayIcon);

      systray_icon = rand(16,16,3); trayimage = im2java(systray_icon); handles.java.TrayIcon = java.awt.TrayIcon(trayimage); java.awt.SystemTray.getSystemTray.add(handles.java.TrayIcon);

      Thanks for your great work,

      Alexander

    • Alexander May 4, 2012 at 02:56 Reply

      Addendum:

      After turning off com.mathworks.widgets.desk.DTDocumentBar.wantsToHandle, also

      com.mathworks.widgets.tooltip.ToolTipAndComponentAWTListener.mouseInTipComponent
      throws an error. But this is not part of the event_listener list.

  4. Anonymous May 15, 2009 at 04:37 Reply

    Please replace with this condition:

    str.indexOf('com.mathworks.mwswing.desk.DTSelectionManager')>=0 || ...
    str.indexOf('javax.swing.plaf.basic.BasicLookAndFeel')>=0 || ...
    str.indexOf('com.mathworks.widgets.text.mcode.MLintDecorator')>=0

    str.indexOf('com.mathworks.mwswing.desk.DTSelectionManager')>=0 || ... str.indexOf('javax.swing.plaf.basic.BasicLookAndFeel')>=0 || ... str.indexOf('com.mathworks.widgets.text.mcode.MLintDecorator')>=0

    With these 3 event listeners removed, it seems no more exeptions occurs (hopefully).

  5. Zach March 15, 2010 at 14:37 Reply

    This works great – one question I have though, I’m not able to get a uitree to resize when placed in one of the panes this creates:

    fig_handle = figure;
    [tree_pane,split_pane,hDiv] = uisplitpane(fig_handle,'Orientation','horizontal','DividerLocation',0.3,'DividerColor',[0.6 0.6 0.6]);
    [top_pane,bottom_pane,vDiv] = uisplitpane(split_pane,'Orientation','vertical','DividerLocation',0.5,'DividerColor',[0.6 0.6 0.6]);
     
    root_node = uitreenode('Test','Test', [], 0);
    Tree = uitree('v0','Parent',tree_pane,'Root',root_node);
    set(Tree,'Units',get(tree_pane,'Units'));
    size_pane = get(tree_pane,'Position');
    set(Tree,'Position',[0 0 size_pane(3) size_pane(4)]);

    fig_handle = figure; [tree_pane,split_pane,hDiv] = uisplitpane(fig_handle,'Orientation','horizontal','DividerLocation',0.3,'DividerColor',[0.6 0.6 0.6]); [top_pane,bottom_pane,vDiv] = uisplitpane(split_pane,'Orientation','vertical','DividerLocation',0.5,'DividerColor',[0.6 0.6 0.6]); root_node = uitreenode('Test','Test', [], 0); Tree = uitree('v0','Parent',tree_pane,'Root',root_node); set(Tree,'Units',get(tree_pane,'Units')); size_pane = get(tree_pane,'Position'); set(Tree,'Position',[0 0 size_pane(3) size_pane(4)]);

    When the sliders are moved, the uitree doesn’t change size with the pane.

    • Zach May 5, 2010 at 08:53 Reply

      Update, here’s an ugly hack I’ve inserted into uisplitpane so that a uitree correctly resizes if it’s in one of the panes.

      In the updateSubPaneSizes, line 800, I’ve inserted:

      %Z
      hParent = get(hDivider,'ContainerParentHandle');
      tree_handle = findobj(hParent,'UserData','com.mathworks.hg.peer.UITreePeer');
      if(~isempty(tree_handle))
         pixelPos = getPixelPos(hDivider);
         set(tree_handle,'Units','pixels')
         current_tree_pos = get(tree_handle,'Position');
         set(tree_handle,'Position',[current_tree_pos(1) current_tree_pos(2) pixelPos(1)-2 pixelPos(4)]);
         drawnow;
      end

      %Z hParent = get(hDivider,'ContainerParentHandle'); tree_handle = findobj(hParent,'UserData','com.mathworks.hg.peer.UITreePeer'); if(~isempty(tree_handle)) pixelPos = getPixelPos(hDivider); set(tree_handle,'Units','pixels') current_tree_pos = get(tree_handle,'Position'); set(tree_handle,'Position',[current_tree_pos(1) current_tree_pos(2) pixelPos(1)-2 pixelPos(4)]); drawnow; end

      Seems to work well enough.

      Thanks,
      Zach

  6. Yogesh November 23, 2010 at 13:18 Reply

    Yair/Anonymous,

    Where do I insert the following lines to remove the bug with R2008+?

    t=java.awt.Toolkit.getDefaultToolkit()
    ev=t.getAWTEventListeners()
    for i=1:length(ev)
        str=ev(i).getListener().getClass.toString
        if str.indexOf('com.mathworks.mwswing.desk.DTSelectionManager')>=0 || ...
           str.indexOf('javax.swing.plaf.basic.BasicLookAndFeel')>=0
            t.removeAWTEventListener(ev(i))
        end
    end

    t=java.awt.Toolkit.getDefaultToolkit() ev=t.getAWTEventListeners() for i=1:length(ev) str=ev(i).getListener().getClass.toString if str.indexOf('com.mathworks.mwswing.desk.DTSelectionManager')>=0 || ... str.indexOf('javax.swing.plaf.basic.BasicLookAndFeel')>=0 t.removeAWTEventListener(ev(i)) end end

    • Yair Altman November 30, 2010 at 16:12 Reply

      @Yogesh – You can do this anywhere in your Matlab session, or at the beginning of the function. Note that the relevant condition was modified by Anonymous (see the comments above) to:

      str.indexOf('com.mathworks.mwswing.desk.DTSelectionManager') >= 0 || ...
      str.indexOf('javax.swing.plaf.basic.BasicLookAndFeel') >= 0 || ...
      str.indexOf('com.mathworks.widgets.text.mcode.MLintDecorator') >= 0

      str.indexOf('com.mathworks.mwswing.desk.DTSelectionManager') >= 0 || ... str.indexOf('javax.swing.plaf.basic.BasicLookAndFeel') >= 0 || ... str.indexOf('com.mathworks.widgets.text.mcode.MLintDecorator') >= 0

  7. uiinspect | Undocumented Matlab January 24, 2013 at 07:07 Reply

    […] In a general case where we might wish to embed Matlab graphs in one of the side panels, we would need to employ a more sophisticated solution (see my UISplitPane utility). […]

  8. Rich-contents log panel | Undocumented Matlab September 18, 2013 at 07:01 Reply

    […] Draggable (resizable) panel borders (note that this feature does not work in the new HG2 – I hope it will be fixed by the time that HG2 is released) […]

  9. Ben January 3, 2014 at 11:58 Reply

    I know this is an old topic but I had a question/problem I hope someone can help me with.

    Using the example from the file exchange I noticed that the mouse pointer no longer updates. Example, select the “zoom in” button, mouse over an axes and the pointer does not change. However, it still functions correctly. Is there a way to fix this so the Pan/Zoom/Etc. positioning controls retain the correct mouse pointer.

  10. Sebas October 14, 2014 at 01:16 Reply

    Ciao Yair!
    It seems that the suggestions to remove all those Java exception (even with the conditions update) do not work with Matlab 2013b onward. It is a shame as the power of what you are sharing is amazing! Is there any chance to provide us some working code so we can take advantage of your very great job? 😉
    Many thanks!

    Seb

  11. Mollie September 28, 2015 at 18:18 Reply

    Hi Yair,

    I recently updated to Matlab 2015a and thus updated my UISplitPane method in my program. I was using your previous UISplitPane method on Matlab 2012a and referenced a property called ‘offsetPosition,’ it was stored within plotDivider; is there a reason why this is not written into the Matlab 2015a version?

    Also, in the old UISplitPane method, there was a line “G.Z.updateSubPaneSIzes = @updateSubPaneSizes” so that I could call updateSubPaneSizes elsewhere in the program, do you have a suggestion for how I could call updateSubPaneSizes outside of UISplitPane?

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