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
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
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
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
% 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
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);
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');
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:
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.
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.
I’m trying to use your solutions, but they do not work (I’m using MATLAB 2008b)…
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!