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'); |
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 |
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 |
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.
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).
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?
@Alex – you are correct: the missing code line is:
-Yair
Hi,
Im trying to make the title of tabs bold but am having some trouble using html doing it. I tried using
But this doesnt seem to work, any suggestions? Thanks
@John –
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.:
Again thanks for the documentation, keep that good stuff coming!
Greetz
-Mark
Hi
I really find your blog extremely useful for our GUI development.
In your close button example, you use the callback
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).
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:
Note: you would probably also want to fix the container’s Position property, not just it’s Parent.
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
This will create very narrow tabs:
Is there a property that can be set to adjust the tab width?
kind regards
Johan
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.
In trying to make the title of tabs font size but I am having some trouble using html.
But this doesnt seem to work, any suggestions?
Thanks
@Hiro – setForeground is used to set the foreground color, not the font. Try one of these alternatives:
Note that HTML formatting of the title string overrides any Java-based customization.
Is it possible to implement this on a MATLAB uitabgroup?
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.
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.
Hello Mr. Altman,
I believe there is trouble with R2014b. Here is my code, just as you have it listed above:
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: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!
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:
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.
hello, any hints why the (close) button does not show up on R2015a (linux64)?
i have a
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.
Good night,
I was wondering If there’s a way to edit the background color of a uitabgroup. Thanks in advance. 🙂
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:
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.
Try adding
drawnow(); pause(0.1)
– https://undocumentedmatlab.com/blog/matlab-and-the-event-dispatch-thread-edtHello Yair,
Thank you for the timely reply. Per you suggestion, I flushed the EDT queue and pending graphics operations using drawnow(); pause(0.1) prior to getting the underlying Java reference. However, this method too was unsuccessful in R2015b. The Java reference still comes back empty (handle: 1-by-0).
I ran the same script on R2015a, and it was successful. Have you experienced similar problems with R2015b?
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
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.
please how can i change the icon in the figure (what i mean is the small icon of matlab in the top,left ?????
Hi Yair,
I’m trying to access some hidden properties (Matlab 2015b, Win7), the following code gives me an empty jTabGroup:
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,
returns an empty matrix. Am I missing something?
Thanks,
Yishai
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:
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:
@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:
Hi Yair,
when I run your code:
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
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
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:
Hello again Mr. Altman and thank you for all you work and help!
I have a question. I want to resize the TABS, i mean the small things at the top, that says “tab1, tab2,….” they are incredible small. I searched an eternity for a solution but cant find it. I tried fontsize and jLabel size but they are not resizing. They stay in a fixed height. the width is stretching accordingly to the amount of text but not the height itself. Do you know a solution? I am working with Matlab 2013b.
Greetings
Peter
@Peter – tab heights are set by the Operating System’s Look and Feel. You can either change the Look-and-Feel used by Matlab, or use the much larger tabs in the GUI Layout Toolbox (GUILT).
It’s working! THANK YOU!!
jTabGroup = getappdata(handle(hTabGroup),'JTabbedPane');
doesn’t work anymore in R2023b 🙁
when i do
jTabGroup = findjobj(hTabGroup,'class','MJTabbedPane');
I get an object of class
javahandle_withcallbacks.com.mathworks.mwswing.MJTabbedPane
But when I call e.g.
jTabGroup.setForegroundAt(0,java.awt.Color(1.0,1,1));
on it, I just get
“Incorrect number or types of inputs or outputs for function setForegroundAt.”