Uitab colors, icons and images

A few months ago I published a post about Matlab’s semi-documented tab-panel functionality, where I promised a follow-up article on tab customizations. A reader of this blog asked a related question earlier today, so I decided it’s about time I fulfilled this promise.

As with most Matlab controls, the underlying Java component enables far greater customization than possible using plain Matlab. Today I will show three specific customizations. We start with a basic tab group, and get the underlying Java component:

% Prevent an annoying warning msg
warning off MATLAB:uitabgroup:OldVersion
 
% Prepare a tab-group consisting of two tabs
hTabGroup = uitabgroup; drawnow;
tab1 = uitab(hTabGroup, 'title','Panel 1');
a = axes('parent', tab1); surf(peaks);
tab2 = uitab(hTabGroup, 'title','Panel 2');
uicontrol(tab2, 'String','Close', 'Callback','close(gcbf)');
 
% Get the underlying Java reference (use hidden property)
jTabGroup = getappdata(handle(hTabGroup),'JTabbedPane');

Foreground & background tab colors

We can set the tab font color using setForeground() and setForegroundAt(), or via HTML. Note that setForegroundAt() overrides anything set by setForeground(). Also remember that Java uses 0-based indexing so tab #1 is actually the second tab:

% Equivalent manners to set a red tab foreground:
jTabGroup.setForegroundAt(1,java.awt.Color(1.0,0,0)); % tab #1
jTabGroup.setTitleAt(1,'<html><font color="red"><i>Panel 2');
jTabGroup.setForeground(java.awt.Color.red);

Unfortunately, the corresponding setBackgroundAt(tabIndex,color) method has no visible effect, and the Matlab-extended tabs keep their white/gray backgrounds. A similar attempt to modify the tab’s BackgroundColor property fails, since Matlab made this property unmodifiable (=’none’). A simple solution is to use a CSS background:

% Equivalent manners to set a yellow tab background:
jTabGroup.setTitleAt(0,'<html><div style="background:#ffff00;">Panel 1');
jTabGroup.setTitleAt(0,'<html><div style="background:yellow;">Panel 1');

uitabgroup with non-default forground and background tab colors and fonts

uitabgroup with non-default forground and background tab colors and fonts

We can set the foreground text color using the CSS color directive. Similarly, we can also set a background gradient image for the tabs, using the CSS background-image directive. Which leads us to our next customization:

Icon images

Icons and sub-components can be added to the tabs. Unfortunately, for some reason that I do not fully understand, jTabGroup.setIconAt() has no apparent effect. The solution is to set our own custom control as the requested tab, and add our icon (or other customizations) to it. Here is a simple example:

% Add an icon to tab #1 (=second tab)
icon = javax.swing.ImageIcon('C:\Yair\save.gif');
jLabel = javax.swing.JLabel('Tab #2');
jLabel.setIcon(icon);
jTabGroup.setTabComponentAt(1,jLabel);	% Tab #1 = second tab
 
% Note: icon is automatically grayed when label is disabled
jLabel.setEnabled(false);
jTabGroup.setEnabledAt(1,false);  % disable only tab #1

tab with a custom icon (enabled)
tab with a custom icon (enabled)

tab with a custom icon (enabled & disabled)

Close buttons

Now let’s try a more complex example, of adding a close (‘x’) button to one of the tabs. Generalizing this code snippet is left as an exercise to the reader:

% First let's load the close icon
jarFile = fullfile(matlabroot,'/java/jar/mwt.jar');
iconsFolder = '/com/mathworks/mwt/resources/';
iconURI = ['jar:file:/' jarFile '!' iconsFolder 'closebox.gif'];
icon = javax.swing.ImageIcon(java.net.URL(iconURI));
 
% Now let's prepare the close button: icon, size and callback
jCloseButton = handle(javax.swing.JButton,'CallbackProperties');
jCloseButton.setIcon(icon);
jCloseButton.setPreferredSize(java.awt.Dimension(15,15));
jCloseButton.setMaximumSize(java.awt.Dimension(15,15));
jCloseButton.setSize(java.awt.Dimension(15,15));
set(jCloseButton, 'ActionPerformedCallback',@(h,e)delete(tab2));
 
% Now let's prepare a tab panel with our label and close button
jPanel = javax.swing.JPanel;	% default layout = FlowLayout
set(jPanel.getLayout, 'Hgap',0, 'Vgap',0);  % default gap = 5px
jLabel = javax.swing.JLabel('Tab #2');
jPanel.add(jLabel);
jPanel.add(jCloseButton);
 
% Now attach this tab panel as the tab-group's 2nd component
jTabGroup.setTabComponentAt(1,jPanel);	% Tab #1 = second tab

tab with an attached close button

tab with an attached close button

Next week’s article will conclude the series on Matlab’s uitab. Any particular customization you are interested in? Please do post a comment.

Addendum Oct 3 2014: the uitab and uitabgroup functions have finally become fully supported and documented in Matlab version 8.4 (R2014b). However, the Java-based customizations shown in this article are still unsupported and undocumented, although they remain practically unchanged from what I’ve described in this article, four years earlier.

Categories: GUI, Icons, Java, Medium risk of breaking in future versions, Semi-documented function

Tags: , , , , , ,

Bookmark and SharePrint Print

39 Responses to Uitab colors, icons and images

  1. Alex says:

    If I execute the following code, the Tab with the icon is not greyed out. It is obviously disabled because I cant click on it, but it looks exactly like an enabled tab. (Icon and Label ar not grey).

    % Prepare a tab-group consisting of two tabs
    hTabGroup = uitabgroup; drawnow;
    tab1 = uitab(hTabGroup, 'title','Panel 1');
    a = axes('parent', tab1); surf(peaks);
    tab2 = uitab(hTabGroup, 'title','Panel 2');
    uicontrol(tab2, 'String','Close', 'Callback','close(gcbf)');
     
    % Get the underlying Java reference (use hidden property)
    jTabGroup = getappdata(handle(hTabGroup),'JTabbedPane');
     
    % Add an icon to tab #1 (=second tab)
    icon = javax.swing.ImageIcon('Find.gif');
    jLabel = javax.swing.JLabel('Tab #2');
    jLabel.setIcon(icon);
    jTabGroup.setTabComponentAt(1,jLabel);	% Tab #1 = second tab
     
    % Note: both label &amp; icon automatically grayed when disabled
    jTabGroup.setEnabledAt(1,false);  % disable only tab #1

    If I comment the paragraph titled with “% Add an icon to tab #1”, the tab is greyed out properly (without icon). You wrote that icons are automatically greyed out, but I can’t get it to work. Does this code work on your computer?

  2. john says:

    Hi,

    Im trying to make the title of tabs bold but am having some trouble using html doing it. I tried using

    jTabGroup.setForeground(java.awt.Font.BOLD);

    But this doesnt seem to work, any suggestions? Thanks

  3. Mark says:

    Hi,

    Thank you for this great “un”documentation! It found instant use in my GUI. :-)
    I did realize that adding a jLabel together with a close button makes the tab look a bit odd as the label then takes the color of the figure background instead of the tab itself (which can also be seen on the above image of the tab with closebutton). I tried to find the source of this behaviour and found that adding either jLabel or close button would lead to it. In the above picture of a jLabel with an icon however everything looks normal….
    Anyhow, i solved the problem by setting the jPanel ‘Opaque’-property to ‘off’, i.e.:

    set(jPanel.getLayout, 'Hgap',0, 'Vgap',0);  %default gap=5px
    set(jPanel,'Opaque','off');

    Again thanks for the documentation, keep that good stuff coming!

    Greetz
    -Mark

  4. Etienne says:

    Hi
    I really find your blog extremely useful for our GUI development.
    In your close button example, you use the callback

    set(jCloseButton, 'ActionPerformedCallback',@(h,e)delete(tab2));

    I have no clue of what the @(h,e) construction does. Could you explain ?

    • @Etienne – this is the standard way that Matlab callbacks are defined: h is the callback’ed object (in this case, jCloseButton), e is the eventData object that holds information about the callback event. A full explanation is available here.

      In this case, @(h,e) is simply an inline definition of a simple function that accepts h and e, and does “delete(tab2)” (no need for either h or e in this particular case).

  5. Yigit Koyuncuoglu says:

    Hello Yair
    I have a question about using the uitree. As I understand uitree accepts generally figure handles. Is it possible to use an uitab handle instead of figure handle. For example, I have a GUI having four tabs, but I want to put an uitree object to only 2nd tab. Because uitree use figure handles, it appears in all tabs. Is it possible to solve this problem?

    • @Yigit – I explained how to do this in my post on uitree:

      uitrees are always created as a direct child of the containing figure, ignoring creation-time Parent values. However, the Parent property can be modified following the tree’s creation:

      [mtree, container] = uitree('v0', 'Root','C:\', 'Parent',tab1); % Parent is ignored
      set(container, 'Parent', tab1);  % fix the uitree Parent

      Note: you would probably also want to fix the container’s Position property, not just it’s Parent.

  6. Johan says:

    Hello Yair,

    I am using tabs aligned to the left.

    It seems like the title of the first tab added to hTabGroup sets the width of all tabs.

    Example:

    This will create very wide tabs

    %Create tabs
    hTabGroup = uitabgroup(gcf,'TabLocation','Left'); 
    tab1 = uitab(hTabGroup, 'title','1 -------------------------------------');
    a = axes('parent', tab1); surf(peaks);
    tab2 = uitab(hTabGroup, 'title','2');
    b = uicontrol(tab2, 'Style','pushbutton','String','Close', 'Callback','close(gcbf)');

    This will create very narrow tabs:

    %Create tabs
    hTabGroup = uitabgroup(gcf,'TabLocation','Left'); 
    tab1 = uitab(hTabGroup, 'title','1');
    a = axes('parent', tab1); surf(peaks);
    tab2 = uitab(hTabGroup, 'title','2 --------------------------------------');
    b = uicontrol(tab2, 'Style','pushbutton','String','Close', 'Callback','close(gcbf)');

    Is there a property that can be set to adjust the tab width?

    kind regards
    Johan

    • Johan says:

      Also, horizontal alignment of the title is set to centered, this looks very weird when titles of different length are used.

      Is there any way to change this?

    • @Johan – simply use TabLocation=’top’ or ‘bottom’. When you use ‘left’ or ‘right’ the tabs are all set to the same width, because otherwise they would not align one on top of the other. This is not a problem with top/left and so in those cases the tabs automatically use a dynamic width.

  7. Hiro says:

    In trying to make the title of tabs font size but I am having some trouble using html.

    jTabGroup.setForeground(java.awt.Fontsize.9)

    But this doesnt seem to work, any suggestions?
    Thanks

    • Yair Altman says:

      @Hiro – setForeground is used to set the foreground color, not the font. Try one of these alternatives:

      % Alternative #1 - HTML (pure Matlab)
      set(hTab, 'Title', 'tab title')
       
      % Alternative #2 - Java (requires *NON*-HTML tab title)
      jTabGroup = getappdata(handle(hTabGroup), 'JTabbedPane')
      jTabGroup.setFont(java.awt.Font('Arial',0,18))

      Note that HTML formatting of the title string overrides any Java-based customization.

  8. Mike says:

    Is it possible to implement this on a MATLAB uitabgroup?

    % First let's load the close icon
    jarFile = fullfile(matlabroot,'/java/jar/mwt.jar');
    iconsFolder = '/com/mathworks/mwt/resources/';
    iconURI = ['jar:file:/' jarFile '!' iconsFolder 'closebox.gif'];
    icon = javax.swing.ImageIcon(java.net.URL(iconURI));
     
    % Now let's prepare the close button: icon, size and callback
    jCloseButton = handle(javax.swing.JButton,'CallbackProperties');
    jCloseButton.setIcon(icon);
    jCloseButton.setPreferredSize(java.awt.Dimension(15,15));
    jCloseButton.setMaximumSize(java.awt.Dimension(15,15));
    jCloseButton.setSize(java.awt.Dimension(15,15));
    set(jCloseButton, 'ActionPerformedCallback',@(h,e)delete(tab2));

    Sorry if this is obvious, I’m new to MATLAB.

    • @Mike – I posted this code on this very page, so why would you think it was not possible???
      If you’re not sure how it works, simply run it in your Matlab. It won’t bite – I promise.

    • Mike says:

      I guess I wasn’t clear. What I was asking is how do you implement tho son a uitab grouped with uitabgroup to close SelectedTab. it looks like you enter set(jCloseButton, ‘ActionPerformedCallback’,@(h,e)delete(tab2)); and it will only delete the item ‘tab2’. Am I way off base here?

      Thanks for the quick reply.

    • @Mike – indeed: in this specific example the close-button will only close tab2. You need to set a similar ActionPerformedCallback for any close button that you create.

  9. David M says:

    Hello Mr. Altman,

    I believe there is trouble with R2014b. Here is my code, just as you have it listed above:

    hTabGroup = uitabgroup; drawnow;
    tab1 = uitab(hTabGroup, 'title', 'Panel 1');
    a = axes('parent',tab1); surf(peaks);
    tab2 = uitab(hTabGroup, 'title', 'Panel 2');
    uicontrol(tab2, 'String', 'Close', 'Callback', 'close(gcbf)');
     
    % Get the underlying Java reference (use hidden property)
    jTabGroup = getappdata(handle(hTabGroup),'JTabbedPane');
     
    % load the close icon
    jarFile = fullfile(matlabroot,'/java/jar/mwt.jar');
    iconsFolder = '/com/mathworks/mwt/resources/';
    iconURI = ['jar:file:/' jarFile '!' iconsFolder 'closebox.gif'];
    icon = javax.swing.ImageIcon(java.net.URL(iconURI));
     
    % Prepare the close button: icon, size and callback
    jCloseButton = handle(javax.swing.JButton,'CallbackProperties');
    jCloseButton.setIcon(icon);
    jCloseButton.setPreferredSize(java.awt.Dimension(15,15));
    jCloseButton.setMaximumSize(java.awt.Dimension(15,15));
    jCloseButton.setSize(java.awt.Dimension(15,15));
    set(jCloseButton, 'ActionPerformedCallback',@(h,e)delete(tab2));
     
    % Prepare a tab panel with our label and close button
    jPanel = javax.swing.JPanel; % default layout = FlowLayout
    set(jPanel.getLayout, 'Hgap',0, 'Vgap',0);  %  default gap = 5px
    jLabel = javax.swing.JLabel('Tab #2');
    jPanel.add(jLabel);
    jPanel.add(jCloseButton);
     
    % Attach this tab panel as the tab-group's 2nd component
    jTabGroup.setTabComponentAt(1,jPanel)	% Tab #1 = second tab

    However, when I attempt to run this script, the following error message occurs:

    Attempt to reference field of non-structure array.

    Error in Untitled2 (line 32)
    jTabGroup.setTabComponentAt(1,jPanel) % Tab #1 = second tab

    Everything worked fine in 2014a. Any ideas?

    Thanks you for you time and efforts.

    • @David – indeed, in R2014b, MathWorks have removed the Java peer reference from hTabGroup‘s ApplicationData, so you get an empty array. Instead, use the findjobj utility:

      jTabGroup = getappdata(handle(hTabGroup), 'JTabbedPane');
      if isempty(jTabGroup)
          jTabGroup = findjobj(hTabGroup);
          jTabGroup = jTabGroup(end);  % in case several handles are returned
      end
    • David M says:

      Many thanks, Yair. Your solution works very well.

      I have just ordered your new book, Accelerating Matlab Performance. I am looking forward to exploring it!

  10. Christian T says:

    Hello Yair,

    when i’m trying to use your example for uitab close buttons, i always get the Error Message:
    No appropriate method, property, or field setTabComponentAt for class matlab.graphics.chart.primitive.Surface. or
    on this line:

    jTabGroup.setTabComponentAt(1,jPanel)	% Tab #1 = second tab

    basicly all jTabGroup Methods trigger this error message. (setTitleAt, setFont)

    Matlab Version is r2014b
    Java Version: Java 1.7.0_11-b21 with Oracle Corporation Java HotSpot(TM) 64-Bit Server VM mixed mode

    I used the findobj Workaround to get the jTabGroup handle.

    • @Christian – apparently you are not accessing the tab-group handle but a plain graphics surface handle. Follow the instructions in my blog to get the correct Java tabgroup handle.

  11. gep says:

    hello, any hints why the (close) button does not show up on R2015a (linux64)?
    i have a

    jTabGroup =
    	javahandle_withcallbacks.com.mathworks.mwswing.MJTabbedPane

    from findjobj utility, so i assume i got the correct handle. Also no errors at all.. I can change icon, dimension, label and gaps but the button is not visible/functional.

  12. Carlos says:

    Good night,

    I was wondering If there’s a way to edit the background color of a uitabgroup. Thanks in advance. :)

  13. David M says:

    Hi Yair,

    In R2015b, on many occasions, I receive an empty handle (handle: 1-by-0) when attempting to get the underlying Java reference by any method (getappdata, findjobj, etc.). Take, for instance, the following script:

    % Get the underlying Java reference (use hidden property)
    jTabGroupViewing = getappdata(handle(hTabGroup), 'JTabbedPane');
     
    if isempty(jTabGroupViewing)
        jTabGroupViewing = findjobj(hTabGroup);
        jTabGroupViewing = jTabGroupViewing(end);  % in case several handles are returned
    end

    Note, my figure is visible and not hidden when I attempt to run this script. Strangely, it will sometimes (randomly) return the Java reference, but it will cause the figure to sporadically scroll through the menu bar options. Quite odd behavior.

    Note, also, everything worked well in R2015a.. I am running Windows 7.

  14. Ondrej says:

    Hi Yair,

    I am using Matlab2008a (7.6.0) on Linux and for some reason most of your great “hacks” has no effect. Even the simple example with red italic tab title

    jTabGroup.setForegroundAt(1,java.awt.Color(1.0,0,0)); % tab #1
    jTabGroup.setTitleAt(1,'<html><font color="red"><i>Panel 2');
    jTabGroup.setForeground(java.awt.Color.red);

    Makes the text red but not italic.

    Also I cannot get to work to get any icon onto the tab (any of your examples). Is this because of the old Matlab version?

    Thanks.
    Ondrej

    • @Ondrej – you should double-check your code to ensure that you use valid HTML syntax.

      Still, many things [especially the advanced stuff that I regularly write about in this blog] will not work on such an old version as R2008a, which is almost 20 releases behind the latest Matlab release.

  15. manel says:

    please how can i change the icon in the figure (what i mean is the small icon of matlab in the top,left ?????

  16. Yishai E says:

    Hi Yair,

    I’m trying to access some hidden properties (Matlab 2015b, Win7), the following code gives me an empty jTabGroup:

    % Prepare a tab-group consisting of two tabs
    hTabGroup = uitabgroup; drawnow;
    tab1 = uitab(hTabGroup, 'title','Panel 1');
    a = axes('parent', tab1); surf(peaks);
    tab2 = uitab(hTabGroup, 'title','Panel 2');
    uicontrol(tab2, 'String','Close', 'Callback','close(gcbf)');
     
    % Get the underlying Java reference (use hidden property)
    jTabGroup = getappdata(handle(hTabGroup),'JTabbedPane');

    I tried using findjobj as you replied to one of the questions here; if I run the no-output GUI version I can see the entire Java tree with all the objects on it, however,

     o = findjobj(hTabGroup)

    returns an empty matrix. Am I missing something?

    Thanks,
    Yishai

  17. Dani says:

    On Matlab 2017a findjobj(hTabGroup) does not seem to find the underlying java handle any longer. Probably the same in earlier releases (see comments above). Any way we can still do uitab java magic in new Matlab versions?

    • @Dani – it works fine for me – perhaps your specific GUI has a problem that causes a problem for findjobj to find the underlying java handle:

      jHandles = findjobj(hTabGroup);
      jTabbedPane = jHandles(end);
  18. Eric says:

    Yair,
    I have a tab group positioned on the left using TabLocation and i am ok with the auto-sizing of the tabs to fit the longest tab name, but for all the tab names i would like them left justified. Trying to do this by setting the title property of the tab using an HTML string doesn’t seem to work. Is there a work around for this? Example code below:

    hTabGroup2 = uitabgroup;
    tab1 = uitab(hTabGroup2,'title','Tab #1');
    tab2 = uitab(hTabGroup2,'title','This is a very long tab');
    tab3 = uitab(hTabGroup2,'title','Tab #3');
    set(hTabGroup2,'TabLocation','left')
     
    set(tab1,'Title','Tab #1')
    • @Eric – HTML alignments only work within the area that the control allocates for the contents. It so happens that Java Swing allocates a tightly-fitting area for controls, so we basically have 3 options:

      • Use a fixed-width font and right-pad with spaces
      • Get the underlying Java handle of the tab-group and modify the Java properties (this became very difficult in recent Matlab releases)
      • Enlarge the allocated area dynamically via pure Matlab and HTML: We first get the width of the tabs, then we set the tab’s title to be a left-aligned table having the same fixed width as the tab (minus a bit due to the margins):
        pos = getpixelposition(tab1);
        tab1.Title = sprintf('<html><table align=left width=%d>Tab #1', pos(1)-4);
  19. Thomas says:

    Hi Yair,

    when I run your code:

    figure 
    % Prepare a tab-group consisting of two tabs
    hTabGroup = uitabgroup; drawnow;
    tab1 = uitab(hTabGroup, 'title','Panel 1');
    a = axes('parent', tab1); surf(peaks);
    tab2 = uitab(hTabGroup, 'title','Panel 2');
    uicontrol(tab2, 'String','Close', 'Callback','close(gcbf)');
     
    % Get the underlying Java reference (use hidden property)
    jTabGroup = getappdata(handle(hTabGroup),'JTabbedPane');
     
    % Add an icon to tab #1 (=second tab)
    icon = javax.swing.ImageIcon('Find.gif');
    jLabel = javax.swing.JLabel('Tab #2');
    jLabel.setIcon(icon);
    jTabGroup.setTabComponentAt(1,jLabel);	% Tab #1 = second tab
     
    % Note: both label & icon automatically grayed when disabled
    jTabGroup.setEnabledAt(1,false);  % disable only tab #1

    I get the following error message. Can you tell me what’s wrong? or Would you please send me your code that works fine?

    Thanks,
    Maz

  20. Michi says:

    Hi Yair,
    many thanks for the excellent and very interesting work arounds! I am currently struggling with the example you provided. When I run your code

    % Prevent an annoying warning msg
    warning off MATLAB:uitabgroup:OldVersion
     
    % Prepare a tab-group consisting of two tabs
    hTabGroup = uitabgroup; drawnow;
    tab1 = uitab(hTabGroup, 'title','Panel 1');
    a = axes('parent', tab1); surf(peaks);
    tab2 = uitab(hTabGroup, 'title','Panel 2');
    uicontrol(tab2, 'String','Close', 'Callback','close(gcbf)');
     
    % Get the underlying Java reference (use hidden property)
    jTabGroup = getappdata(handle(hTabGroup),'JTabbedPane');
     
    % Equivalent manners to set a red tab foreground:
    jTabGroup.setForegroundAt(1,java.awt.Color(1.0,0,0)); % tab #1
    jTabGroup.setTitleAt(1,'<i>Panel 2');
    jTabGroup.setForeground(java.awt.Color.red);
     
    % Equivalent manners to set a yellow tab background:
    jTabGroup.setTitleAt(0,'Panel 1');
    jTabGroup.setTitleAt(0,'Panel 1');

    the following error shows up:
    Dot indexing is not supported for variables of this type.

    Executing your code line by line indicates that the error is prompted for the first time when executing
    jTabGroup.setForegroundAt(1,java.awt.Color(1.0,0,0)); % tab #1

    I am using MATLAB Version: 9.5.0.1033004 (R2018b) Update 2.

    Many thanks for your help!

    • @Michi – in recent Matlab releases Matlab no longer stores the Java handle in the tab-group’s ApplicationData property, so using getappdata() returns an empty array, causing the error that you see. Instead of using getappdata, us the findjobj utility:

      jTabGroup = findjobj(hTabGroup,'class','MJTabbedPane');

Leave a Reply

Your email address will not be published. Required fields are marked *