Last week, I presented the undocumented uisplittool and uitogglesplittool functions and showed how they can be added to a Matlab figure toolbar. Today I wish to conclude this topic by explaining how these controls can be customized with user-defined callbacks and pop-up menus.
Callback functionality
Both uisplittool and uitogglesplittool have a Callback property, in addition to the standard ClickedCallback property that is available in uipushtools and uitoggletools.
The standard ClickedCallback is invoked when the main button is clicked, while Callback is invoked when the narrow arrow button is clicked. uitogglesplittool, like uitoggletool, also has settable OnCallback and OffCallback callback properties.
The accepted convention is that ClickedCallback should invoke the default control action (in our case, an Undo/Redo of the topmost uiundo action stack), while Callback should display a drop-down of selectable actions.
While this can be done programmatically using the Callback property, this functionality is already pre-built into uisplittool and uitogglesplittool for our benefit. To access it, we need to get the control’s underlying Java component.
Accessing the underlying Java component is normally done using the findjobj utility, but in this case we have a shortcut: the control handle’s hidden JavaContainer property that holds the underlying com.mathworks.hg.peer.SplitButtonPeer (or .ToggleSplitButtonPeer) Java reference handle. This Java object’s MenuComponent property returns a reference to the control’s drop-down sub-component (which is a com.mathworks.mwswing.MJPopupMenu object):
>> jUndo = get(hUndo,'JavaContainer') jUndo = com.mathworks.hg.peer.SplitButtonPeer@f09ad5 >> jMenu = get(jUndo,'MenuComponent') % or: =jUndo.getMenuComponent jMenu = com.mathworks.mwswing.MJPopupMenu[Dropdown Picker ButtonMenu,...] |
Let’s add a few simple textual options:
jOption1 = jMenu.add('Option #1'); jOption1 = jMenu.add('Option #2'); set(jOption1, 'ActionPerformedCallback', 'disp(''option #1'')'); set(jOption2, 'ActionPerformedCallback', {@myCallbackFcn, extraData}); |
Popup-menus are described in more detail elsewhere (and in future articles). In the past I have already explained how icons and HTML markup can be added to menu items. Sub-menus can also be added.
A complete example
Let’s now use this information, together with last year’s set of articles about Matlab’s undocumented uiundo functionality, to generate a complete and more realistic example, of undo/redo toolbar buttons.
Undo and redo are actions that are particularly suited for uisplittool, since its main button enables us to easily undo/redo the latest action (like a simple toolbar button, by clicking the main uisplittool button) as well as select items from the actions drop-down (like a combo-box, by clicking the attached arrow button) – all this using a single component.
% Display our GUI hEditbox = uicontrol('style','edit', 'position',[20,60,40,40]); set(hEditbox, 'Enable','off', 'string','0'); hSlider = uicontrol('style','slider','userdata',hEditbox); set(hSlider,'Callback',@test_uiundo); % Display the figure toolbar that was hidden by the uicontrol function set(gcf,'Toolbar','figure'); % Add the Undo/Redo buttons hToolbar = findall(gcf,'tag','FigureToolBar'); hUndo = uisplittool('parent',hToolbar); hRedo = uitogglesplittool('parent',hToolbar); % Load the Redo icon icon = fullfile(matlabroot,'/toolbox/matlab/icons/greenarrowicon.gif'); [cdata,map] = imread(icon); % Convert white pixels into a transparent background map(find(map(:,1)+map(:,2)+map(:,3)==3)) = NaN; % Convert into 3D RGB-space cdataRedo = ind2rgb(cdata,map); cdataUndo = cdataRedo(:,[16:-1:1],:); % Add the icon (and its mirror image = undo) to latest toolbar set(hUndo, 'cdata',cdataUndo, 'tooltip','undo','Separator','on', ... 'ClickedCallback','uiundo(gcbf,''execUndo'')'); set(hRedo, 'cdata',cdataRedo, 'tooltip','redo', ... 'ClickedCallback','uiundo(gcbf,''execRedo'')'); % Re-arrange the Undo/Redo buttons jToolbar = get(get(hToolbar,'JavaContainer'),'ComponentPeer'); jButtons = jToolbar.getComponents; for buttonIdx = length(jButtons)-3 : -1 : 7 % end-to-front jToolbar.setComponentZOrder(jButtons(buttonIdx), buttonIdx+1); end jToolbar.setComponentZOrder(jButtons(end-2), 5); % Separator jToolbar.setComponentZOrder(jButtons(end-1), 6); % Undo jToolbar.setComponentZOrder(jButtons(end), 7); % Redo jToolbar.revalidate; % Retrieve redo/undo object undoObj = getappdata(gcf,'uitools_FigureToolManager'); if isempty(undoObj) undoObj = uitools.FigureToolManager(gcf); setappdata(gcf,'uitools_FigureToolManager',undoObj); end % Populate Undo actions drop-down list jUndo = get(hUndo,'JavaContainer'); jMenu = get(jUndo,'MenuComponent'); undoActions = get(undoObj.CommandManager.UndoStack,'Name'); jMenu.removeAll; for actionIdx = length(undoActions) : -1 : 1 % end-to-front jActionItem = jMenu.add(undoActions(actionIdx)); set(jActionItem, 'ActionPerformedCallback', @myUndoCallbackFcn); end jToolbar.revalidate; % Drop-down callback function function myUndoCallbackFcn(jActionItem,hEvent) % user processing needs to be placed here end % myUndoCallbackFcn |
In a real-world application, the code-segment above that populated the drop-down list would be placed within the slider’s test_uiundo() callback function, and we would set a similar drop-down for the hRedu button. In addition, we would dynamically modify the button tooltips. As a final customization, we could modify the figure’s main menu. Menu customization will be discussed in a future separate set of articles.
Have you used uisplittool or uitogglesplittool in your GUI? If so, please tell us what use you have made of them, in a comment below.
Hello Yair,
this site is great!
I am using the togglesplittool in my GUI. First I had problems, Matlab 2010a shutting down. I was able to solve this by putting a “pause(0.01)” before calling “get(hUndo,’JavaContainer’)”.
You know a way to put a sign like you have on uimenus by setting the ‘checked’-property to ‘on’?
Greetings Chris
@Chris – I don’t follow you: where do you want the check sign and under which conditions do you want it to appear/disappear?
Exactly, i give different options the user can choose from the togglesplittool associated drop-down-menu. After choosing one can click the togglebutton. Now it would be nice if the user can see the actually selected option. This i would like to do by putting a sign check to the last selected option from the drop-down-menu. I hope you got what i mean?