In the past weeks I’ve shown how Matlab menus can be customized in a variety of undocumented manners, using HTML, pure Matlab, and Java. Today I conclude this mini-series with an article that explains how to use the underlying Java object to customize menu item icons. Menu customizations are explored in depth in section 4.6 of my book.
A reminder: accessing the underlying Java object
Matlab menus (uimenu) are basically simple wrappers for the much more powerful and flexible Java Swing
JMenuItem on which they are based. Many important functionalities that are available in Java menus are missing from the Matlab uimenus.
Getting the Java reference for the figure window’s main menu is very easy:
jFrame = get(handle(hFig),'JavaFrame'); try % R2008a and later jMenuBar = jFrame.fHG1Client.getMenuBar; catch % R2007b and earlier jMenuBar = jFrame.fFigureClient.getMenuBar; end
There are many customizations that can only be done using the Java handle: setting icons, several dozen callback types, tooltips, background color, font, text alignment, and so on. etc. Interested readers may wish to get/set/inspect/methodsview/uiinspect the
jSave reference handle and/or to read the documentation for
JMenuItem. Today’s article will focus on icon customizations.
Setting simple menu item icons
Many of Matlab’s icons reside in either the [matlabroot ‘/toolbox/matlab/icons/’] folder or the [matlabroot ‘/java/jar/mwt.jar’] file (a JAR file is simply a zip file that includes Java classes and resources such as icon images). Let us create icons from the latter, to keep a consistent look-and-feel with the rest of Matlab (we could just as easily use our own external icon files):
% External icon file example jSave.setIcon(javax.swing.ImageIcon('C:\Yair\save.gif')); % JAR resource example jarFile = fullfile(matlabroot,'/java/jar/mwt.jar'); iconsFolder = '/com/mathworks/mwt/resources/'; iconURI = ['jar:file:/' jarFile '!' iconsFolder 'save.gif']; iconURI = java.net.URL(iconURI); % not necessary for external files jSave.setIcon(javax.swing.ImageIcon(iconURI));
Note that setting a menu item’s icon automatically re-aligns all other items in the menu, including those that do not have an icon (an internal bug that was introduced in R2010a causes a misalignment, as shown below):
The empty space on the left of the menu is reserved for the check mark. Each Matlab menu item is check-able, since it is an object that extends the
com.mathworks.mwswing.MJCheckBoxMenuItem class. I have not found a way to eliminate this empty space, which is really unnecessary in the File-menu case (it is only actually necessary in the View and Tools menus). Note that if an icon is set for the item, both the icon and the checkmark will be displayed, side by side.
The check mark is controlled by the State property of the Java object (which accepts logical true/false values), or the Checked property of the Matlab handle (which accepts the regular ‘on’/’off’ string values):
% Set the check mark at the Matlab level set(findall(hFig,'tag','figMenuFileSave'), 'Checked','on'); % Equivalent - set the checkmark at the Java level jSave.setState(true);
Customizing menu icons
Icons can be customized: modify the gap between the icon and the label with the IconTextGap property (default = 4 [pixels]); place icons to the right of the label by setting HorizontalTextPosition to
jSave.LEFT (=2), or centered using
jSave.CENTER (=0). Note that the above-mentioned misalignment bug does not appear in these cases:
Note how the label text can be seen through (or on top of) the icon when it is centered. This feature can be used to create stunning menu effects as shown below. Note how the width and height of the menu item automatically increased to accommodate my new 77×31 icon size (icons are normally sized 16×16 pixels):
To resize an icon programmatically before setting it in a Java component, we can use the following example:
myIcon = fullfile(matlabroot,'/toolbox/matlab/icons/matlabicon.gif'); imageToolkit = java.awt.Toolkit.getDefaultToolkit; iconImage = imageToolkit.createImage(myIcon); iconImage = iconImage.getScaledInstance(32,32,iconImage.SCALE_SMOOTH); jSave.setIcon(javax.swing.ImageIcon(iconImage));
Remember when rescaling images, particularly small ones with few pixels, that it is always better to shrink than to enlarge images: enlarging a small icon image might introduce a significant pixelization effect:
Separate icons can be specified for a different appearance during mouse hover (RolloverIcon; requires RolloverEnabled=1), item click/press (PressedIcon), item selection (SelectedIcon, RolloverSelectedIcon, DisabledSelectedIcon), and disabled menu item (DisabledIcon). All these properties are empty () by default, which applies a predefined default variation (image color filter) to the main item’s Icon. For example, let us modify DisabledIcon:
myIcon = 'C:\Yair\Undocumented Matlab\Images\save_disabled.gif'; jSaveAs.setDisabledIcon(javax.swing.ImageIcon(myIcon)); jSaveAs.setEnabled(false);
Note the automatic graying of disabled menu items, including their icon. This effect can also be achieved programmatically using the static methods in
com.mathworks.mwswing.IconUtils: changeIconColor(), createBadgedIcon(), createGhostedIcon(), and createSelectedIcon(). When we use a non-default custom DisabledIcon, it is used instead of the gray icon variant.
This concludes my mini-series of customizing menus in Matlab. If you have used any nifty customization that I have not mentioned, please post a comment about it below.
In an unrelated note, I would like to extend good wishes to Mike Katz, who has left the MathWorks mobile development team to join Kinvey a few days ago. Mike has been with MathWorks since 2005 and has been responsible for maintaining the official MATLAB Desktop blog, together with Ken Orr. I’m not sure yet which direction the Desktop blog will take, and by whom, but in any case it won’t be the same. You’re both missed, Mike & Ken!
Yair, is there any way to have the menu remain open after clicking it? Suppose you wanted to have a menu with a bunch of booleans, and you wanted to be able to quickly change the state of a bunch of them without doing click, reopen, click, reopen….