Undocumented Matlab
  • SERVICES
    • Consulting
    • Development
    • Training
    • Gallery
    • Testimonials
  • PRODUCTS
    • IQML: IQFeed-Matlab connector
    • IB-Matlab: InteractiveBrokers-Matlab connector
    • EODML: EODHistoricalData-Matlab connector
    • Webinars
  • BOOKS
    • Secrets of MATLAB-Java Programming
    • Accelerating MATLAB Performance
    • MATLAB Succinctly
  • ARTICLES
  • ABOUT
    • Policies
  • CONTACT
  • SERVICES
    • Consulting
    • Development
    • Training
    • Gallery
    • Testimonials
  • PRODUCTS
    • IQML: IQFeed-Matlab connector
    • IB-Matlab: InteractiveBrokers-Matlab connector
    • EODML: EODHistoricalData-Matlab connector
    • Webinars
  • BOOKS
    • Secrets of MATLAB-Java Programming
    • Accelerating MATLAB Performance
    • MATLAB Succinctly
  • ARTICLES
  • ABOUT
    • Policies
  • CONTACT

Customizing menu items part 2

May 2, 2012 14 Comments

Last week I explained how to customize Matlab’s menu items using some undocumented tricks that do not need Java. Today I will show how using just a tiny bit of Java magic powder we can add much more complex customizations to menu items. Menu customizations are explored in depth in section 4.6 of my book.

Accessing the underlying Java object

Matlab menus (uimenu) are basically simple wrappers for the much more powerful and flexible Java Swing JMenu and 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

jFrame = get(handle(hFig),'JavaFrame'); try % R2008a and later jMenuBar = jFrame.fHG1Client.getMenuBar; catch % R2007b and earlier jMenuBar = jFrame.fFigureClient.getMenuBar; end

Note that we have used the figure handle’s hidden JavaFrame property, accessed through the reference’s handle() wrapper, to prevent an annoying warning message.
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. Some useful examples are provided below.

Dynamic menu behavior

As a first example of Java-based customization, let us add DHTML-like behavior to the menu, such that the menu items will automatically be displayed when the mouse hovers over the item, without waiting for a user mouse click. First, get the jMenuBar reference as described above. Now, set the MouseEnteredCallback to automatically simulate a user mouse click on each menu item using its doClick() method. Setting the callback should be done separately to each of the top-level menu components:

for menuIdx = 1 : jMenuBar.getComponentCount
    jMenu = jMenuBar.getComponent(menuIdx-1);
    hjMenu = handle(jMenu,'CallbackProperties');
    set(hjMenu,'MouseEnteredCallback','doClick(gcbo)');
end

for menuIdx = 1 : jMenuBar.getComponentCount jMenu = jMenuBar.getComponent(menuIdx-1); hjMenu = handle(jMenu,'CallbackProperties'); set(hjMenu,'MouseEnteredCallback','doClick(gcbo)'); end

Note that using this mechanism may be awkward if the top-level menu does not have a sub-menu but is rather a stand-alone menu item. For example, if the top-level menu-item “Help” is a stand-alone menu button (i.e., there are no help menu-items, just the single Help item), then moving the mouse over this item will trigger the help event, although the user did not actually click on the item. To prevent this behavior, we should modify the code snippet above to only work on those menu items that have sub-items.

Custom accelerator shortcut keys

As another example, Matlab automatically assigns a non-modifiable keyboard accelerator key modifier of , while JMenus allow any combination of Alt/Ctrl/Shift/Meta (depending on the platform). Let us modify the default File/Save accelerator key from ‘Ctrl-S’ to ‘Alt-Shift-S’ as an example. We need a reference for the “Save” menu item. Note that unlike regular Java components, menu items are retrieved using the getMenuComponent() method and not getComponent():

% File main menu is the first main menu item => index=0
jFileMenu = jMenuBar.getComponent(0);
% Save menu item is the 5th menu item (separators included)
jSave = jFileMenu.getMenuComponent(4); %Java indexes start with 0!
inspect(jSave) 	% just to be sure: label='Save' => good!
% Finally, set a new accelerator key for this menu item:
jAccelerator = javax.swing.KeyStroke.getKeyStroke('alt shift S');
jSave.setAccelerator(jAccelerator);

% File main menu is the first main menu item => index=0 jFileMenu = jMenuBar.getComponent(0); % Save menu item is the 5th menu item (separators included) jSave = jFileMenu.getMenuComponent(4); %Java indexes start with 0! inspect(jSave) % just to be sure: label='Save' => good! % Finally, set a new accelerator key for this menu item: jAccelerator = javax.swing.KeyStroke.getKeyStroke('alt shift S'); jSave.setAccelerator(jAccelerator);

That is all there is to it – the label is modified automatically to reflect the new keyboard accelerator key. More info on setting different combinations of accelerator keys and modifiers can be found in the official Java documentation for KeyStroke.

Modification of menu item accelerator and tooltip
Modification of menu item accelerator and tooltip

Note that 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. The File menu does NOT need to remain open – it only needs to have been opened sometime earlier, for its menu items to be rendered. This can be done either interactively (by selecting the File menu) or programmatically:

% Simulate mouse clicks to force the File main-menu to open & close
jFileMenu.doClick; % open the File menu
jFileMenu.doClick; % close the menu
% Now the Save menu is accessible:
jSave = jFileMenu.getMenuComponent(4);

% Simulate mouse clicks to force the File main-menu to open & close jFileMenu.doClick; % open the File menu jFileMenu.doClick; % close the menu % Now the Save menu is accessible: jSave = jFileMenu.getMenuComponent(4);

Tooltip and highlight

For some unknown reason, MathWorks did not include a tooltip property in its Matlab menu handle, contrary to all the other Matlab GUI components. So we must use the Java handle, specifically the ToolTipText property:

jSave.setToolTipText('modified menu item with tooltip');

jSave.setToolTipText('modified menu item with tooltip');

Java menu items also contain a property called Armed, which is a logical value (default=false). When turned on, the menu item is highlighted just as when it is selected (see the Save As… menu item in the screenshot above). On a Windows system, this means a blue background:

jSave.setArmed(true);

jSave.setArmed(true);

When the item is actually selected and then de-selected, Armed reverts to a false (off) value. Alternating the Armed property value can achieve an effect of flashing the menu item.

Callbacks

In addition to the standard Swing control callbacks discussed in an earlier article, menu items possess several additional callbacks that are specific to menu items, including:

  • ActionPerformedCallback – fired when the menu item is invoked
  • StateChangedCallback – fired when the menu item is selected or deselected
  • MenuDragMouseXXXCallback (XXX=Dragged/Entered/Exited/Released) – fired when the menu item is dragged, for the corresponding event
  • MenuKeyXXXCallback (XXX=Pressed/Released/Typed) – fired when a keyboard click event occurs (the menu item’s accelerator was typed)

Using these callbacks, together with the 30-odd standard Swing callbacks, we can control our menu’s behavior to a much higher degree than possible using the standard Matlab handle.
Next week, I will conclude this mini-series with an article explaining how to customize menu item icons.

Related posts:

  1. Customizing menu items part 3 – Matlab menu items can easily display custom icons, using just a tiny bit of Java magic powder. ...
  2. Customizing listbox/combobox items – Matlab listboxes can be customized using custom Java cell-renderers. ...
  3. Customizing menu items part 1 – Matlab menus can be customized in a variety of undocumented manners - first article of a series. ...
  4. Customizing editboxes – Matlab's editbox can be customized in many useful manners...
  5. Customizing the standard figure toolbar, menubar – The standard figure toolbar and menubar can easily be modified to include a list of recently-used files....
  6. Customizing combobox popups – Matlab combobox (dropdown) popups can be customized in a variety of ways. ...
Callbacks GUI Java JavaFrame Menubar Undocumented feature
Print Print
« Previous
Next »
14 Responses
  1. Attilio Funel June 19, 2012 at 03:39 Reply

    Hi!

    I’m trying to use your solutions, but they do not work (I’m using MATLAB 2008b)…

    myGUI = figure('Visible','on','Name','Urania alternativa DB Utility',...
                        'MenuBar','none', ...            %No menu bar 
                        'NumberTitle', 'off', ...
                        'Position',[360,500,450,285]);
    set(myGUI,'CloseRequestFcn',@EditMenuExitFunction);
    ChangeIcon(myGUI);
     
    jFrame = get(handle(myGUI),'JavaFrame');
    try
        jMenuBar = jFrame.fHG1Client.getMenuBar;
    catch
    end
     
    editMenu = uimenu(myGUI,'Label','Edit');
    jEditMenu = jMenuBar.getComponent(0);
    hjMenu = handle(jEditMenu,'CallbackProperties');
    set(hjMenu,'MouseEnteredCallback','doClick(gcbo)');
    editMenuOpen = uimenu(editMenu, 'Label', 'Open DB', ..., 
                        'Accelerator', 'O',...
                        'Callback', @EditMenuOpenFunction);

    myGUI = figure('Visible','on','Name','Urania alternativa DB Utility',... 'MenuBar','none', ... %No menu bar 'NumberTitle', 'off', ... 'Position',[360,500,450,285]); set(myGUI,'CloseRequestFcn',@EditMenuExitFunction); ChangeIcon(myGUI); jFrame = get(handle(myGUI),'JavaFrame'); try jMenuBar = jFrame.fHG1Client.getMenuBar; catch end editMenu = uimenu(myGUI,'Label','Edit'); jEditMenu = jMenuBar.getComponent(0); hjMenu = handle(jEditMenu,'CallbackProperties'); set(hjMenu,'MouseEnteredCallback','doClick(gcbo)'); editMenuOpen = uimenu(editMenu, 'Label', 'Open DB', ..., 'Accelerator', 'O',... 'Callback', @EditMenuOpenFunction);

    It crashes at jEditMenu = jMenuBar.getComponent(0);…
    The strange thing is that if I put a breakpoint there, and I execute the following steps, THEY WORK!! I’m really puzzled. I fear there’s some lack of alignment between the MATLAB and Java interpreters when I run the program, or something stranger.

    Ciao and thanks!

    • Attilio Funel June 19, 2012 at 06:10 Reply

      Just one correction: I’m using 2010a. I also tried to remove the option ‘MenuBar’, ‘none’, but with just slightly better results. It executes cycle on children of MenuBar; however, when I try to pick sons of first item (menu ‘File’) they are zero!! This does not happen if I execute the instructions one by one with the debugger.

    • Yair Altman June 19, 2012 at 08:15 Reply

      @Attilio – the reason for this was explained in the EDT article. Basically, it takes time to display the figure and it may not yet be ready by the time you run the Java functions. The solution is either to add a call to drawnow (possibly with an additional pause(0.1)) right after your ChangeIcon() call, or use the javaMethodEDT/awtinvoke functions when running the Java functionality. For more details see the EDT article.

      • Attilio Funel June 20, 2012 at 02:23

        Hi! Thanks a lot for the suggestions, now it works… though partially. Perhaps I’m missing something else. The problem now is when I attempt to change items of the menu, it keeps saying “Edit” has 0 components…

        editMenu = uimenu(myGUI,'Label','Edit');
        editMenuOpen = uimenu(editMenu, 'Label', 'Open DB', ..., 
                            'Accelerator', 'O',...
                            'Callback', @EditMenuOpenFunction);
        drawnow;
        editMenuSave = uimenu(editMenu, 'Label', 'Save DB', ...
                            'Accelerator', 'S', ...
                            'Callback', @EditMenuSaveFunction, ...
                            'Enable', 'off');
         
        %Se ho acceduto come attiliosfunel abilito "Save"
        if(strcmp(accessedUserName, 'attiliosfunel') == true)
            set(editMenuSave,'Enable','on');
        end
        drawnow;
        editMenuClose = uimenu(editMenu, 'Label', 'Close DB', ...
                            'Callback', @EditMenuCloseFunction, ...
                            'Accelerator', 'C');
        drawnow;
        editMenuExit = uimenu(editMenu, 'Label', 'Exit', ...
                            'Accelerator', 'X', ...
                            'Callback', @EditMenuExitFunction);
        drawnow;
        pause(0.1);
         
        %Handle della finestra
        jFrame = get(handle(myGUI),'JavaFrame');
        try
           jMenuBar = jFrame.fHG1Client.getMenuBar;
        catch ERROR_GET_HANDLE_WINDOW
        end
         
        jEditMenu = jMenuBar.getComponent(0);
        jEditMenu.getComponentCount

        editMenu = uimenu(myGUI,'Label','Edit'); editMenuOpen = uimenu(editMenu, 'Label', 'Open DB', ..., 'Accelerator', 'O',... 'Callback', @EditMenuOpenFunction); drawnow; editMenuSave = uimenu(editMenu, 'Label', 'Save DB', ... 'Accelerator', 'S', ... 'Callback', @EditMenuSaveFunction, ... 'Enable', 'off'); %Se ho acceduto come attiliosfunel abilito "Save" if(strcmp(accessedUserName, 'attiliosfunel') == true) set(editMenuSave,'Enable','on'); end drawnow; editMenuClose = uimenu(editMenu, 'Label', 'Close DB', ... 'Callback', @EditMenuCloseFunction, ... 'Accelerator', 'C'); drawnow; editMenuExit = uimenu(editMenu, 'Label', 'Exit', ... 'Accelerator', 'X', ... 'Callback', @EditMenuExitFunction); drawnow; pause(0.1); %Handle della finestra jFrame = get(handle(myGUI),'JavaFrame'); try jMenuBar = jFrame.fHG1Client.getMenuBar; catch ERROR_GET_HANDLE_WINDOW end jEditMenu = jMenuBar.getComponent(0); jEditMenu.getComponentCount

        The last call jEditMenu.getComponentCount returns 0…

      • Yair Altman June 20, 2012 at 02:29

        @Attilio – Now you forgot to call doClick() as explained in the article. If you need any further customizations or help with your program please contact me via email (altmany at gmail).

        In the future, please reply on the original comment thread, rather than creating a new thread.

  2. sebbo December 4, 2012 at 05:30 Reply

    Hi,

    I’m having trouble with the doClick-method…
    I have no problem finding the menu and getting it to open with menu.doClick().
    But it won’t close on the next menu.doClick() call.

    I already inserted drawnow’s and pause(1) statements between the doClick-calls, but that doesn’t help either – the menu simply remains open, even when I have a loop running à la:

    while true
        menu.doClick()
        pause(1);
    end

    while true menu.doClick() pause(1); end

    Are there other ways to force the menu to hide again?

    • Roger Svensson August 22, 2013 at 09:01 Reply

      Late answer but maybe useful for others with the same problem. Issue the following to close any open menus:

      javax.swing.MenuSelectionManager.defaultManager().clearSelectedPath();

      javax.swing.MenuSelectionManager.defaultManager().clearSelectedPath();

  3. Stephan Heise October 30, 2013 at 05:18 Reply

    Hi!

    In your post you play with the figure window

    • Yair Altman October 30, 2013 at 07:21 Reply

      I don’t understand your question…

  4. Stephan Heise November 7, 2013 at 00:30 Reply

    Oops – it seems as though most of my question got lost – sorry for that. Here it is again:

    In your post you play with the main menu of the figure window. I would like to do similar stuff with a uicontextmenu (e.g. adding icons). However, I have so far been unsuccessful in finding the according Java reference for the context menu. Could you help me with that, please?

    • Yair Altman November 11, 2013 at 03:47 Reply

      @Stephan – as far as I can tell, Matlab’s context-menus are not implemented in Java and so they cannot be modified in the same manner. Instead of using Matlab’s context menus, you can easily implement your own Java-based context-menu (which is much more customizable), as I have shown here: http://undocumentedmatlab.com/blog/setting-listbox-mouse-actions/

  5. Thierry Dalon November 28, 2013 at 01:21 Reply

    The setAccelerator method throws an error:
    http://docs.oracle.com/javase/7/docs/api/javax/swing/JMenu.html

    public void setAccelerator(KeyStroke keyStroke)
    setAccelerator is not defined for JMenu. Use setMnemonic instead.
    Overrides:
    setAccelerator in class JMenuItem
    Parameters:
    keyStroke - the keystroke combination which will invoke the JMenuItem's actionlisteners without navigating the menu hierarchy
    Throws:
    Error - if invoked -- this method is not defined for JMenu. Use setMnemonic instead
    
    • Yair Altman November 28, 2013 at 01:43 Reply

      @Thierry – you have looked at the incorrect javadoc: JMenu is the top-level menu (File/Edit/View/… – the jFileMenu item in my article above) and for that you cannot set an accelerator – it is automatically set by the operating system, e.g. <Alt>-F to activate the File main menu.

      However, accelerators work just fine for menu items that are not top-level (JMenuItem, or rather com.mathworks.mwswing.MJCheckBoxMenuItem which extends it). If you try the code you’ll see that it works just fine. The relevant javadoc for these menu items is: http://docs.oracle.com/javase/7/docs/api/javax/swing/JMenuItem.html#setAccelerator(javax.swing.KeyStroke)

      • Thierry Dalon November 28, 2013 at 04:15

        sorry and thank you Yair for the prompt reply. I was using JMenu.getItem instead of jMenu.getMenuComponent as you advised. It works as you advise.

Leave a Reply
HTML tags such as <b> or <i> are accepted.
Wrap code fragments inside <pre lang="matlab"> tags, like this:
<pre lang="matlab">
a = magic(3);
disp(sum(a))
</pre>
I reserve the right to edit/delete comments (read the site policies).
Not all comments will be answered. You can always email me (altmany at gmail) for private consulting.

Click here to cancel reply.

Useful links
  •  Email Yair Altman
  •  Subscribe to new posts (feed)
  •  Subscribe to new posts (reader)
  •  Subscribe to comments (feed)
 
Accelerating MATLAB Performance book
Recent Posts

Speeding-up builtin Matlab functions – part 3

Improving graphics interactivity

Interesting Matlab puzzle – analysis

Interesting Matlab puzzle

Undocumented plot marker types

Matlab toolstrip – part 9 (popup figures)

Matlab toolstrip – part 8 (galleries)

Matlab toolstrip – part 7 (selection controls)

Matlab toolstrip – part 6 (complex controls)

Matlab toolstrip – part 5 (icons)

Matlab toolstrip – part 4 (control customization)

Reverting axes controls in figure toolbar

Matlab toolstrip – part 3 (basic customization)

Matlab toolstrip – part 2 (ToolGroup App)

Matlab toolstrip – part 1

Categories
  • Desktop (45)
  • Figure window (59)
  • Guest bloggers (65)
  • GUI (165)
  • Handle graphics (84)
  • Hidden property (42)
  • Icons (15)
  • Java (174)
  • Listeners (22)
  • Memory (16)
  • Mex (13)
  • Presumed future risk (394)
    • High risk of breaking in future versions (100)
    • Low risk of breaking in future versions (160)
    • Medium risk of breaking in future versions (136)
  • Public presentation (6)
  • Semi-documented feature (10)
  • Semi-documented function (35)
  • Stock Matlab function (140)
  • Toolbox (10)
  • UI controls (52)
  • Uncategorized (13)
  • Undocumented feature (217)
  • Undocumented function (37)
Tags
AppDesigner (9) Callbacks (31) Compiler (10) Desktop (38) Donn Shull (10) Editor (8) Figure (19) FindJObj (27) GUI (141) GUIDE (8) Handle graphics (78) HG2 (34) Hidden property (51) HTML (26) Icons (9) Internal component (39) Java (178) JavaFrame (20) JIDE (19) JMI (8) Listener (17) Malcolm Lidierth (8) MCOS (11) Memory (13) Menubar (9) Mex (14) Optical illusion (11) Performance (78) Profiler (9) Pure Matlab (187) schema (7) schema.class (8) schema.prop (18) Semi-documented feature (6) Semi-documented function (33) Toolbar (14) Toolstrip (13) uicontrol (37) uifigure (8) UIInspect (12) uitable (6) uitools (20) Undocumented feature (187) Undocumented function (37) Undocumented property (20)
Recent Comments
Contact us
Captcha image for Custom Contact Forms plugin. You must type the numbers shown in the image
Undocumented Matlab © 2009 - Yair Altman
This website and Octahedron Ltd. are not affiliated with The MathWorks Inc.; MATLAB® is a registered trademark of The MathWorks Inc.
Scroll to top