Archive for the ‘Icons’ Category

Figure toolbar components

Thursday, August 27th, 2009

Toolbars are by now a staple of modern GUI design. An unobtrusive list of small icons enables easy access to multiple application actions without requiring large space for textual descriptions. Unfortunately, the built-in documented support for the Matlab toolbars is limited to adding icon buttons via the uipushtool and uitoggletool functions, and new toolbars containing them via the uitoolbar function. In this post I will introduce several additional customizations that rely on undocumented features.

This article will only describe figure toolbars. However, much of the discussion is also relevant to the desktop (Comand Window) toolbars and interested users can adapt it accordingly.

Accessing toolbar buttons - undo/redo

Let’s start by adding undo/redo buttons to the existing figure toolbar. I am unclear why such an elementary feature was not included in the default figure toolbar, but this is a fact that can easily be remedied. In a future post I will describe uiundo, Matlab’s semi-documented support for undo/redo functionality, but for the present let’s assume we already have this functionality set up.

First, let’s prepare our icons, which are basically a green-filled triangle icon and its mirror image:

% 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],:);

Now let’s add these icons to the default figure toolbar:

% Add the icon (and its mirror image = undo) to the latest toolbar
hUndo = uipushtool('cdata',cdataUndo, 'tooltip','undo', 'ClickedCallback','uiundo(gcbf,''execUndo'')');
hRedo = uipushtool('cdata',cdataRedo, 'tooltip','redo', 'ClickedCallback','uiundo(gcbf,''execRedo'')');

Undo/redo buttons

Undo/redo buttons

In the preceding screenshot, since no figure toolbar was previously shown, uipushtool added the undo and redo buttons to a new toolbar. Had the figure toolbar been visible, then the buttons would have been added to its right end. Since undo/redo buttons are normally requested near the left end of toolbars, we need to rearrange the toolbar buttons:

hToolbar = findall(hFig,'tag','FigureToolBar');
%hToolbar = get(hUndo,'Parent');  % an alternative
hButtons = findall(hToolbar);
set(hToolbar,'children',hButtons([4:end-4,2,3,end-3:end]));
set(hUndo,'Separator','on');

Undo/redo buttons in their expected positions

Undo/redo buttons in their expected positions

We would normally preserve hUndo and hRedo, and modify their Tooltip and Visible/Enable properties in run-time, based on the availability and name of the latest undo/redo actions:

% Retrieve redo/undo object
undoObj = getappdata(hFig,'uitools_FigureToolManager');
if isempty(undoObj)
   undoObj = uitools.FigureToolManager(hFig);
   setappdata(hFig,'uitools_FigureToolManager',undoObj);
end
 
% Customize the toolbar buttons
latestUndoAction = undoObj.CommandManager.peekundo;
if isempty(latestUndoAction)
   set(hUndo, 'Tooltip','', 'Enable','off');
else
   tooltipStr = ['undo' latestUndoAction.Name];
   set(hUndo, 'Tooltip',tooltipStr, 'Enable','on');
end

We can easily adapt the method I have just shown to modify/update existing toolbar icons: hiding/disabling them etc. based on the application needs at run-time.

Adding non-button toolbar components - undo dropdown

A more advanced customization is required if we wish to present the undo/redo actions in a drop-down (combo-box). Unfortunately, since Matlab only enables adding uipushtools and uitoggletools to toolbars, we need to use a Java component. The drawback of using such a component is that it is inaccessible via the toolbar’s Children property (implementation of the drop-down callback function is left as an exercise to the reader):

% Add undo dropdown list to the toolbar
jToolbar = get(get(hToolbar,'JavaContainer'),'ComponentPeer');
if ~isempty(jToolbar)
   undoActions = get(undoObj.CommandManager.UndoStack,'Name');
   jCombo = javax.swing.JComboBox(undoActions(end:-1:1));
   set(jCombo, 'ActionPerformedCallback', @myUndoCallbackFcn);
   jToolbar(1).add(jCombo,5); %5th position, after printer icon
   jToolbar(1).repaint;
   jToolbar(1).revalidate;
end
 
% Drop-down (combo-box) callback function
function myUndoCallbackFcn(hCombo,hEvent)
   itemIndex = get(hCombo,'SelectedIndex');  % 0=topmost item
   itemName  = get(hCombo,'SelectedItem');
   % user processing needs to be placed here
end

Undo dropdown list

Undo dropdown list

Note that the javax.swing.JComboBox constructor accepts a cell-array of strings (undoActions in the snippet above). A user-defined dropdownlist might be constructed as follows (also see a related CSSM thread):

...
dropdownStrings = {'here', 'there', 'everywhere'};
jCombo = javax.swing.JComboBox(dropdownStrings);
set(jCombo, 'ActionPerformedCallback', @myUndoCallbackFcn);
jToolbar(1).addSeparator;
jToolbar(1).add(jCombo);  % at end, following a separator mark
jToolbar(1).repaint;
jToolbar(1).revalidate;
...

A similar approach can be used to add checkboxes, radio-buttons and other non-button controls.

In next week’s post I will describe how the toolbar can be customized using undocumented functionality to achieve a non-default background, a floating toolbar (”palette”) effect and other interesting customizations. If you have any specific toolbar-related request, I’ll be happy to hear in the comments section below.

Bookmark and Share

Setting system tray popup messages

Tuesday, March 31st, 2009

Continuing my previous post about setting system-tray icons, I will now show how to set informational popup messages next to these icons.

Asynchronous informational messages can be presented next to the sys-tray icon, in a fashion similar to what we came to expect from modern programs. This could be used to indicate some unexpected event that was detected, or the end of a complex calculation phase. The message title, text and severity icon are all customizable.

Unfortunately, the Java method used to display messages, java.awt.TrayIcon.displayMessage(), expects an object of type java.awt.TrayIcon.MessageType, which is an enumeration within the TrayIcon class. However, Matlab’s dot-notation does not recognize what should have been the following correct notation, so we need to resort to Java reflection:

>> trayIcon.displayMessage('title','info msg',TrayIcon.MessageType.INFO);
??? No appropriate method or public field MessageType for class java.awt.TrayIcon

>> trayIconClasses = trayIcon.getClass.getClasses;
>> trayIconClasses(1)
ans =
class java.awt.TrayIcon$MessageType	<= hurray!!!
>> MessageTypes = trayIconClasses(1).getEnumConstants
MessageTypes =
java.awt.TrayIcon$MessageType[]:
    [java.awt.TrayIcon$MessageType]	<= 1: ERROR
    [java.awt.TrayIcon$MessageType]	<= 2: WARNING
    [java.awt.TrayIcon$MessageType]	<= 3: INFO
    [java.awt.TrayIcon$MessageType]	<= 4: NONE
>> trayIcon.displayMessage('title','info msg',MessageTypes(3));

systray INFO message

and another example, now with a WARNING icon:

systray WARNING message

If the title string is left empty, then neither title nor the severity icon will be displayed. The message can still be manually dismissed by clicking within its boundaries:


systray messages without a title (hence also without a severity icon)
systray messages without a title (hence also without a severity icon)

Informational popup messages are automatically aligned and positioned by the system. Messages are automatically dismissed by the system after some time, if not dismissed by the user first. The exact time is determined by system and user activity and other such external factors. Informational messages replace one another, if the previous message has still not been cleared by the user.

I have created a utility function called SYSTRAY, which is a convenience function that facilitates the setup and update of system tray icons and messages. SYSTRAY (with source code) can be downloaded from the File Exchange.

I would be happy to hear if and how you’re using the new system-tray functionality in your application - let me know below.

Bookmark and Share

Setting system tray icons

Tuesday, March 24th, 2009

Java 1.6, included in Matlab releases since Matlab 7.5 (R2007b), enables programmatic access to system tray icons on such systems that support this functionality (Windows, Linux and possibly others).  If the SystemTray object indicates that it isSupported(), then a TrayIcon can be added, along with an associated tooltip and popup menu:

sysTray = java.awt.SystemTray.getSystemTray;
if (sysTray.isSupported)
   myIcon = fullfile(matlabroot,'/toolbox/matlab/icons/matlabicon.gif');
   iconImage = java.awt.Toolkit.getDefaultToolkit.createImage(myIcon);
   trayIcon = java.awt.TrayIcon(iconImage, 'initial tooltip');
   trayIcon.setToolTip('click this icon for applicative context menu');
end

sample system tray icon

sample system tray icon

The icon image can be made to automatically resize to the system-tray dimensions, using the trayIcon.setImageAutoSize(true) method (by default the icon image will maintain its original size, getting cropped or appearing small as the case may be).

Of course, after initial setup, all the sys-tray icon’s properties (icon image, popup, tooltip etc.) can be modified with convenient set methods (setImage(), setPopupMenu(), setTooltip()) or via Matlab’s set() function.

Icon popup menus are very similar in concept to Matlab uicontextmenus. Unfortunately, they need to be programmed separately since Java does not accept uicontextmenu handles. This is actually quite easy, as the following code snippet shows:

% Prepare the context menu
menuItem1 = java.awt.MenuItem('action #1');
menuItem2 = java.awt.MenuItem('action #2');
menuItem3 = java.awt.MenuItem('action #3');

% Set the menu items' callbacks
set(menuItem1,'ActionPerformedCallback',@myFunc1);
set(menuItem2,'ActionPerformedCallback',{@myfunc2,data1,data2});
set(menuItem3,'ActionPerformedCallback','disp(''action #3...'')');

% Disable one of the menu items
menuItem2.setEnabled(0);        % or: set(menuItem2,'Enabled','off');

% Add all menu items to the context menu (with internal separator)
jmenu = java.awt.PopupMenu;
jmenu.add(menuItem1);
jmenu.add(menuItem2);
jmenu.addSeparator;
jmenu.add(menuItem3);

% Finally, attach the context menu to the icon
trayIcon.setPopupMenu(jmenu);    % or: set(trayIcon,'PopupMenu',jmenu);

Tray icon context (right-click) menu

Tray icon context (right-click) menu

Unfortunately, neither the icon tooltip nor its popup menu supports HTML. The reason is that SystemTray is actually not part of Swing at all. The system-tray functionality resides in the java.awt package, and does not inherit javax.swing.JLabel’s (and Matlab uicontrols) support for HTML.

I have created a utility function called SYSTRAY, which is a convenience function that facilitates the setup and update of system tray icons. SYSTRAY (with source code) can be downloaded from the File Exchange.

In a separate post, I shall detail how informational pop-up messages can be attached to system-tray icons. This requires a bit of Java-hacking, so is beyond the scope of a single blog post.

Please note the new TODO page, which details my future posts. I would be happy to hear your requests for new topics, or telling me which topics you’d like to see earlier than others.

Addendum (May 15, 2009): A kind reader today left a comment on another post of this blog with a solution for some reported Java exceptions when using systray in Matlab R2008b onward.

Bookmark and Share