A well-known Matlab limitation is that component position vectors must be specified as either ‘normalized’ or some fixed-sized value, but not in combination. For example, we cannot place a button in the center of the screen (normalized x/y=0.5) with a fixed sized width/height. Either all position elements are normalized, or all are fixed. Most Matlab GUIs that I’ve seen keep the normalized units, with the result that buttons look bloated or shrunken when the figure is resized:
hButton = uicontrol('Units','norm', 'Position',[0.5,0.5,0.15,0.15], 'String','click me!');
A common way to address this latter limitation is to use a borderless containing uipanel at the requested normalized position, and place a fixed-sized component as a child of that panel:
bgColor = get(gcf,'Color'); hPanel = uipanel('Units','norm', 'Position',[0.5, 0.5, 0.45, 0.45], 'BorderType','none', 'BackgroundColor',bgColor); hButton = uicontrol('Parent',hPanel, 'Units','pixels', 'Position',[0,0,60,20], 'String','click me!');
This works well in simple figures, where there is nothing beneath the panel/control. Resizing the figure will keep the button centered, while preserving its 60×20 size. But what happens if we have an axes beneath? In this case we encounter another Matlab limitation, that a top-most control always occludes (hides) an overlapped component. This is due to the fact that Matlab GUI uses heavyweight controls and containers, which do not allow transparency. For this reason, we cannot show a plot chart as the background of a table or listbox, for example. The result is that our panel will occlude the axes for a horrible-looking effect:
t = 1:.01:100; plot(t, cos(t), 'r'); bgColor = get(gcf,'Color'); hPanel = uipanel('Units','norm', 'Position',[0.5, 0.5, 0.45, 0.45], 'BorderType','none', 'BackgroundColor',bgColor); hButton = uicontrol('Parent',hPanel, 'Units','pixels', 'Position',[0,0,60,20], 'String','click me!');
Which is where today’s undocumented feature comes in handy: simply set the uipanel’s BackgroundColor to ‘none’ and the panel will become transparent:
The reason that uipanel does not obey the occlusion limitation is simply because it is not really a control at all: Most Matlab GUI controls are simple wrappers for the standard Java Swing component (buttons for
JButton, listboxes for
JListbox etc.). However, uipanel is not a wrapper for
JPanel, as we might have expected, but rather implemented as as internal Matlab component that groups HG objects for onscreen display, and possibly paints the border (a uipanel‘s title is a simple text control once again) as a simple rectangle. This is the reason why Matlab’s borders look so different than
JPanel‘s. This enabled Matlab to include the back-door of the ‘none’ BackgroundColor, which works for panels but not for any other GUI control.
Note that setting the BackgroundColor to ‘none’ issues the following warning that you can ignore at your own risk:
Warning: "Setting the ColorSpec to 'none' for a uicontainer will not be allowed in a future release."
To ignore (and stop issuing) such warnings, simply issue the following Matlab command:
warning off MATLAB:hg:ColorSpec_None warning('off', 'MATLAB:hg:ColorSpec_None'); % equivalent alternative
p.s. – using a transparent panel in this manner is not necessary in certain cases (e.g., when the axes is added after the control, not before it as above). However, relying on such side-effects is not advised at all, for obvious reasons.
I look forward to the day when Matlab controls will be able to become truly transparent, and when the position and size units could be specified separately, so that use of such back-door kludges will not be necessary. After all, designing a GUI is supposed to resemble an art, not brain surgery…
Addendum for HG2 (R2014b onward)
In HG2, the panel’s BackgroundColor can no longer be set to
'none'. Luckily, in HG2 we have a direct reference to the underlying Java JPanel component, as I explained here. We can use this reference by setting it, as well as its direct parent and child components, to be non-opaque, as follows:
jPanel = hPanel.JavaFrame.getPrintableComponent; % hPanel is the Matlab handle to the uipanel jPanel.setOpaque(false) jPanel.getParent.setOpaque(false) jPanel.getComponent(0).setOpaque(false) jPanel.repaint