- Undocumented Matlab - https://undocumentedmatlab.com -

Customizing menu items part 3

Posted By Yair Altman On May 9, 2012 | 39 Comments

In the past weeks I’ve shown how Matlab menus can be customized in a variety of undocumented manners, using HTML, pure Matlab [1], and Java [2]. 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 [3].

A reminder: accessing the underlying Java object

Matlab menus (uimenu) are basically simple wrappers for the much more powerful and flexible Java Swing JMenu and JMenuItem [4] 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 [5] the jSave reference handle and/or to read the documentation for JMenuItem [6]. 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):

Menu item with a custom Icon (R2009b)
Menu item with a custom Icon (R2009b)
   
...and the same in R2010a onward
...and the same in R2010a onward

Checkmark icon

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);

State = true, Icon = [ ]
State = true, Icon = [ ]
   
State = true, Icon = custom
State = true, Icon = custom

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:

jSave.setHorizontalTextPosition(jSave.LEFT)
jSave.setHorizontalTextPosition
(jSave.LEFT)
   
jSave.setHorizontalTextPosition(jSave.CENTER)
jSave.setHorizontalTextPosition
(jSave.CENTER)

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):
Overlaid icon (HorizontalTextPosition = CENTER)
Overlaid icon (HorizontalTextPosition = CENTER)

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:

16x16 icon image resized to 32x32
16x16 icon image resized to 32x32

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);

Enabled, main Icon
Enabled, main Icon
   
Disabled, default Icon variation
Disabled, default Icon variation
   
Disabled, custom DisabledIcon
Disabled, custom DisabledIcon

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 [7].
Ken & MikeIn 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 [8], together with Ken Orr [9]. 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!

 

Categories: GUI, Icons, Java, Medium risk of breaking in future versions, Undocumented feature


39 Comments (Open | Close)

39 Comments To "Customizing menu items part 3"

#1 Comment By John On May 18, 2012 @ 18:49

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

Thanks,
John

#2 Comment By Yair Altman On May 19, 2012 @ 12:44

@John – I don’t believe that you can prevent the menu from closing. But if you trap the menu item’s callback, you could possibly immediately reopen the menu programmatically, as explained in the [16] of this mini-series.

#3 Comment By John On May 19, 2012 @ 14:39

Thanks Yair, I’ll try that.

#4 Comment By Morteza On September 28, 2012 @ 02:53

Hi
You have nice web site and it is very interisting (Thanks)
I tried to insert an icon in Save file menu according to your doc.

figure(1)
jFrame    = get(handle(gcf),'JavaFrame')
jMenuBar  = jFrame.fHG1Client.getMenuBar;
jFileMenu = jMenuBar.getComponent(0)
jMER      = jFileMenu.getMenuComponent(1)
jMER.setIcon(javax.swing.ImageIcon(im2java(A)));

But when MATLAB
reach to below line of my command line :
jMER = jFileMenu.getMenuComponent(1)
it set a message that it is:

Error using com.mathworks.hg.peer.MenuPeer$FigureMJMenu/getMenuComponent
Java exception occurred:
java.lang.ArrayIndexOutOfBoundsException: No such child: 1
	at java.awt.Container.getComponent(Unknown Source)
	at javax.swing.JMenu.getMenuComponent(Unknown Source)

Can you help me please?

#5 Comment By Yair Altman On September 28, 2012 @ 03:03

@Morteza – as I explained in the [17], “the Save menu-item reference can only be retrieved after opening the File menu at least once earlier; otherwise, an exception will be thrown when trying to access the menu item“. Read there for additional details and workaround.

#6 Comment By Morteza On September 29, 2012 @ 08:36

Hi Dear Yair Altman.
It work….
Thank so much

#7 Comment By Morteza On October 2, 2012 @ 10:57

Hi Dear Yair
I try to put the icons for uicontextmenu in my program but I couldn’t. Can you help me.

B.cm = uicontextmenu;
B.um(1) = uimenu(B.cm,'label','Statistical val.',...
                'Callback', {@BM1_call,B},'foregroundcolor',[0.2863 0.0667 0.0157]);   
B.um(2) = uimenu(B.cm,'label','Plot ...','Separator','on',...
                'Callback', {@BM2_call,B},'foregroundcolor',[0.2863 0.0667 0.0157]);

Thanks.

#8 Comment By Yair Altman On October 2, 2012 @ 13:07

@Morteza – You could try to use HTML images, as explained [18]. But perhaps a better way is to use Java icons in a Java context-menu, rather than a Matlab uicontextmenu.

If you have additional programming requests, please contact me by email for personal consulting.

#9 Comment By Morteza On October 11, 2012 @ 05:59

Hi dear Yair
I try to put an image in uicontextmenu by html functions.
I use the : src=”” (function that shows image)

txtimg = 'Color-Map'; 
uimenu(F.cm,'label',txtimg,'Callback',{@FM1_call,F});

Even I put the root directory path like :
but nothing happened and just cross sign is shown.
but when I execute my GUI, MATLAB does not show the image in uicontextmenu.
Can you help me?

#10 Comment By Yair Altman On October 12, 2012 @ 07:43

@Morteza – this will be answered in my [19], so stay tuned…

#11 Comment By Morteza On October 12, 2012 @ 10:28

Hi Dear Yair
I’ll follow your articles…
Thanks anyway

#12 Comment By Morteza On October 16, 2012 @ 12:16

Hi Dear Yair
last part I asked about put the image using of html format.
I use the pwd function in MATLAB and I found there is diffrent root path between Windows and html.
in windows pwd : C:\Program Files\MATLAB\R2012a\bin
but in html format : [20]
‘/’ insted of ‘\’.
but when I try to do this in MATLAB but nothing appear!!!
Is there something that I should use extra?
Thank you so much

#13 Comment By Morteza On October 22, 2012 @ 09:48

Hi Dear Yair
I try to open link of your E-mail from your web-site but I couldn’t.
So,I have a question about subject that I know it is not related to this page article, then excuse me.
Is it possible to write a program after make it as stand-alone application (*.exe) by compiler’s MATLAB ,at specific time delete itself to prevent extra use?
Thanks

#14 Comment By amir On December 24, 2015 @ 10:29

i am amin from iran

maybe use pause …it is possible

#15 Comment By Shuhao Cao On May 18, 2013 @ 16:26

Hi, Yair
Your website is so helpful! I followed some of the matlab customization on your website, now I wonder if I could change the font used in the MATLAB, like I tried something like:

 
com.mathworks.services.Prefs.setFontPref('MenuFont',java.awt.Font('Ubuntu',0,13))

but nothing happened.
Thanks.

#16 Comment By Yair Altman On May 18, 2013 @ 16:40

@Shuhao – after modifying the prefs you need to restart Matlab. You need to ensure (of course) that the relevant preference name exists.

#17 Comment By Shuhao Cao On May 18, 2013 @ 16:57

Thanks for the quick reply. Is there a way to see what are all the relevant preference names?

#18 Comment By Yair Altman On May 18, 2013 @ 16:59

Of course – simply open the preferences file in a text editor

edit([prefdir '/matlab.prf'])

#19 Comment By Shuhao Cao On May 18, 2013 @ 17:05

Haha, I see. Thanks a lot. I have looked into it but found no ‘MenuFont’. Guess there is no easy workaround within MATLAB to change the font size of the menu then.

#20 Comment By Mailf On July 19, 2013 @ 08:24

Hi,
I’ve tried your code:

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));

There is an error on the last line returning this message:
Undefined variable “jSave” or class “jSave.setIcon”.

I’m working on Matlab 2012…

Sébastien

#21 Comment By Yair Altman On July 19, 2013 @ 08:29

This is article #3 in a series. You can’t run code from article 3 without reading articles 1,2 before… jSave is defined in the previous part of this series.

#22 Pingback By Variables Editor scrolling | Undocumented Matlab On September 11, 2013 @ 03:36

[…] having been published in what was then called the Desktop Blog (renamed MATLAB Spoken Here since Ken and Mike have left MathWorks and the blog focus has […]

#23 Comment By Sandro On March 7, 2014 @ 13:26

I’m trying to insert an icon like in your post, but I can not. Could you send by email an example that is running? ie, for me to do ctrl+c ctrl+v. So I will be able to understand better.

#24 Comment By Yair Altman On March 10, 2014 @ 10:09

@Sandro – I would be happy to provide you with my professional consulting services via email. Send me an email via the link at the top-right of this page if you are interested.

#25 Comment By Ilya On October 16, 2014 @ 07:18

Hi Yair,
the great code indeed, it worked perfectly fine, but in R2014b it does not work any more.

 
hFig = figure;
jFrame = get(handle(hFig),'JavaFrame'); % gives warning
% Warning: figure JavaFrame property will be obsoleted in a future release. For more information see
% the JavaFrame resource on the MathWorks web site. 
jMenuBar = jFrame.fHG1Client.getMenuBar; % gives error
% No appropriate method, property, or field fHG1Client for class com.mathworks.hg.peer.HG2FigurePeer.

is there any way around?

#26 Comment By Ilya On October 16, 2014 @ 07:21

ohh, the name has been changed to fHG2Client, why and when????
the following code should be used

jMenuBar = jFrame.fHG2Client.getMenuBar; 

#27 Comment By Yair Altman On October 16, 2014 @ 09:11

@Ilya – I described this over a year ago, in my [21] article.

#28 Comment By Ilya On October 17, 2014 @ 06:31

@Yair – thank you for keeping things updated, it really helps to keep the code running 🙂

#29 Comment By Andre Sell On September 7, 2015 @ 03:37

Hi Yair,
thanks for this interesting possibilities.

I was able to implement icons (and tooltips) for my menus this way. Instead of getMenuBar() I use findjobj to get the handles.

Now I also want to implement icons for some uimenus that are childs of uicontextmenus. Unfortunately findjobj seems not to find uicontextmenus (“No Java reference was found for the requested handle, probably because it is still invisible”) even if it is opened twice. So I look for a child uimenu and then use getParent(). But findjobj seems not to find the uimenu entries that are childs of the uicontextmenu but the ones of the main menu. When I “force” to look only for the one searched by using the ‘property’ option with the tag no handle is found.

Can you help using findjobj to find uicontextmenus or uimenus that are childs of uicontextmenus?

Best regards
André

#30 Comment By Adam Foltz On November 19, 2015 @ 19:32

Hey Yair,

I am creating a GUI in MATLAB 2014a. Using you findjobj utility, I am trying to change the background color of the menu bar and the sub-menus. For some reason none of the backgrounds will change color, but the text will. The menu bar seems to be originated from the Windows environment, but the sub-menus appear to be MATLAB based. Do you know why none of the backgrounds will change color?

Best,
Adam Foltz

#31 Comment By Yair Altman On November 19, 2015 @ 23:31

@Adam – on some modern platforms, the menu items’ bgcolor is dynamically set by the system and cannot easily be overridden. In other words,

jSave.setBackground(java.awt.Color.yellow)

has no visible effect.

However, we can still use HTML/CSS, as follows:

padding = [' &' repmat(' ',1,30)];  % space padding to extend the background area
label = ['Save' padding]; 
jSave.setText(label)

#32 Comment By amir On December 24, 2015 @ 10:16

how can change oreintation menus and uitable to right – left

#33 Comment By Ooms On March 9, 2016 @ 16:18

Hi Yair,

I would like to make the labels editable in the menu itself. For example that you can richt-click on the word ‘Save’, a box pops up where you can select ‘rename’, and that the word ‘Save’ becomes editable. maybe with an editbox style uicontrol at the exact location of the word ‘Save’. Is there a way to do this? What i do now is, i use an inputdlg box. But that is less userfriendly. Below is a function that shows and hides lines in a figure based on their displayname where i’d like to use this.

function showhide(h,a)
   f = findall(gcf,'label','show/hide')
   if numel(f)
      s2=findall(f,'position',2)
      if numel(s2)
         s2.Separator='on'
      end
      if strcmp(h.Label,'add')
         str = inputdlg('enter a string');
         uimenu(f,'label',str{1},'Callback',@showhide);
      else
         l = findall(gcf,'type','line');
         c = char(setdiff({'on' 'off'},get(h,'checked')));
         set(h,'Checked',c);
         set(l(~cellfun('isempty',strfind(get(l,'DisplayName'),h.Label))),'visible',c,'handlevisibility',c);
      end
   else
      f=uimenu(gcf,'label','show/hide');
      uimenu(f,'label','add','Callback',@showhide);
   end
end

#34 Comment By Sneha On July 20, 2017 @ 12:11

Hi Yair,
The article is very helpful.
I tried to execute the commands in a single m-file programatically but got an error.
The error occurred was

Java exception occurred:
java.lang.ArrayIndexOutOfBoundsException: No such child: 0
	at java.awt.Container.getComponent(Unknown Source)
	at javax.swing.JMenu.getMenuComponent(Unknown Source)

if I execute the code one line at a time I did not face any issue .
Could you please help me with the issue

#35 Comment By Yair Altman On July 20, 2017 @ 12:26

@Sneha – as I explained [22], the menu needs to be opened once in order for its menu items to become visible.

#36 Comment By Sneha On July 26, 2017 @ 14:23

Hi Yair,
Apologies for my late reply. I did not attach the code previously sorry for that
The below is the code written

jf = get(hObject,'JavaFrame');
jmb = jf.fHG2Client.getMenuBar;
jFileMenu = jmb.getComponent(0);
jFileMenu.doClick;  %% open menu
jFileMenu.doClick; % close the menu
jvalue1 = jFileMenu.getMenuComponent(0);
jvalue2=jFileMenu.getMenuComponent(1);
jvalue3 = jFileMenu.getMenuComponent(2);

So this code if I execute line by line I am able to get tool tip messages but i run code as a .m file I gt that error

#37 Comment By Yair Altman On November 6, 2017 @ 11:37

@Sneha – add a short drawnow; pause(0.01) between the calls to jFileMenu.doClick and the call to jFileMenu.getMenuComponent.

More information:
* [23]
* [24]

#38 Comment By Le Trong Nhan On January 29, 2019 @ 09:27

Hi Yair,
I am writing MATLAB with using Java in my program; And I use RolloverIcon to set for my button with a image, but when I move mouse into button, my button does not show the image set.
I need a advice from Mr. Yair !

Thanks

#39 Comment By Yair Altman On January 29, 2019 @ 12:46

Using RolloverIcon requires setting RolloverEnabled to true (default=false):

jMenuItem.setRolloverEnabled(true);
jMenuItem.setRolloverIcon(icon1);
jMenuItem.setRolloverSelectedIcon(icon2);

Article printed from Undocumented Matlab: https://undocumentedmatlab.com

URL to article: https://undocumentedmatlab.com/articles/customizing-menu-items-part-3

URLs in this post:

[1] pure Matlab: http://undocumentedmatlab.com/blog/customizing-menu-items-part-1/

[2] Java: http://undocumentedmatlab.com/blog/customizing-menu-items-part-2/

[3] book: http://undocumentedmatlab.com/matlab-java-book/

[4] JMenu and JMenuItem: http://docs.oracle.com/javase/tutorial/uiswing/components/menu.html

[5] uiinspect: http://www.mathworks.com/matlabcentral/fileexchange/17935-uiinspect-display-methods-properties-callbacks-of-an-object

[6] JMenuItem: http://docs.oracle.com/javase/6/docs/api/javax/swing/JMenuItem.html

[7] below: http://undocumentedmatlab.com/blog/customizing-menu-items-part-3/#respond

[8] MATLAB Desktop blog: http://blogs.mathworks.com/desktop/

[9] Ken Orr: http://undocumentedmatlab.com/blog/gui-integrated-browser-control/

[10] Customizing menu items part 2 : https://undocumentedmatlab.com/articles/customizing-menu-items-part-2

[11] Customizing listbox/combobox items : https://undocumentedmatlab.com/articles/customizing-listbox-combobox-items

[12] Customizing menu items part 1 : https://undocumentedmatlab.com/articles/customizing-menu-items-part-1

[13] Customizing uitree nodes – part 1 : https://undocumentedmatlab.com/articles/customizing-uitree-nodes

[14] Customizing Matlab uipanels : https://undocumentedmatlab.com/articles/customizing-matlab-uipanels

[15] Customizing combobox popups : https://undocumentedmatlab.com/articles/customizing-combobox-popups

[16] : https://undocumentedmatlab.com/blog/customizing-menu-items-part-2/#dynamic

[17] : https://undocumentedmatlab.com/blog/customizing-menu-items-part-2/#accelerator

[18] : https://undocumentedmatlab.com/blog/spicing-up-matlab-uicontrol-tooltips/

[19] : https://undocumentedmatlab.com/blog/images-in-matlab-uicontrols-and-labels/

[20] : https://undocumentedmatlab.com/blog/customizing-menu-items-part-3/

[21] : https://undocumentedmatlab.com/blog/hg2-update#observations

[22] : https://undocumentedmatlab.com/blog/customizing-menu-items-part-2

[23] : https://undocumentedmatlab.com/blog/matlab-and-the-event-dispatch-thread-edt

[24] : https://undocumentedmatlab.com/blog/solving-a-matlab-hang-problem

Copyright © Yair Altman - Undocumented Matlab. All rights reserved.