Archive for the ‘Medium risk of breaking in future versions’ Category

Customizing uitree nodes – part 2

Wednesday, September 1st, 2010

In my previous posts I have shown how Matlab’s semi-documented uitree and uitreenode functions can be used to display hierarchical (tree) control in Matlab GUI. Today I conclude this mini-series by answering a reader’s request to show how checkboxes, radio buttons and other similar controls can be attached to tree nodes.

There are actually several ways this can be done:

Matlab icon control

The simplest is to create two icons (checked/unchecked) and switch the node’s icon whenever it is selected (use mtree’s NodeSelectedCallback or jtree’s MouseClickedCallback callbacks) – a sample implementation was posted by Gwendolyn Fischer a couple of years ago, based on even earlier posts by John Anderson, Brad Phelan and me. Here it is, with minor fixes:

function uitree_demo
% function based on treeExperiment6 by John Anderson
% see http://www.mathworks.com/matlabcentral/newsreader/view_thread/104957#269485
%
% The mousePressedCallback part is inspired by Yair Altman
%
% derived from Brad Phelan's tree demo
% create a tree model based on UITreeNodes and insert into uitree.
% add and remove nodes from the treeModel and update the display
import javax.swing.*
import javax.swing.tree.*;
 
% figure window
f = figure('Units', 'normalized');
 
b1 = uicontrol( 'string','add Node', ...
   'units' , 'normalized', ...
   'position', [0 0.5 0.5 0.5], ...
   'callback', @b1_cb);
 
b2 = uicontrol( 'string','remove Node', ...
   'units' , 'normalized', ...
   'position', [0.5 0.5 0.5 0.5], ...
   'callback', @b2_cb);
 
%[I,map] = imread([matlab_work_path, '/checkedIcon.gif']);
[I,map] = checkedIcon;
javaImage_checked = im2java(I,map);
 
%[I,map] = imread([matlab_work_path, '/uncheckedIcon.gif']);
[I,map] = uncheckedIcon;
javaImage_unchecked = im2java(I,map);
 
% javaImage_checked/unchecked are assumed to have the same width
iconWidth = javaImage_unchecked.getWidth;
 
% create top node
rootNode = uitreenode('v0','root', 'File List', [], 0);
% [matlab_work_path, '/fileListIcon.gif'],0);
 
% create two children with checkboxes
cNode = uitreenode('v0','unselected', 'File A', [], 0);
% as icon is embedded here we set the icon via java, otherwise one could
% use the uitreenode syntax uitreenode(value, string, icon, isLeaf) with
% icon being a qualified pathname to an image to be used.
cNode.setIcon(javaImage_unchecked);
rootNode.add(cNode);
 
cNode = uitreenode('v0','unselected', 'File B', [], 0);
cNode.setIcon(javaImage_unchecked);
rootNode.add(cNode);
 
% set treeModel
treeModel = DefaultTreeModel( rootNode );
 
% create the tree
tree = uitree('v0');
tree.setModel( treeModel );
% we often rely on the underlying java tree
jtree = handle(tree.getTree,'CallbackProperties');
% some layout
drawnow;
set(tree, 'Units', 'normalized', 'position', [0 0 1 0.5]);
set(tree, 'NodeSelectedCallback', @selected_cb );
 
% make root the initially selected node
tree.setSelectedNode( rootNode );
 
% MousePressedCallback is not supported by the uitree, but by jtree
set(jtree, 'MousePressedCallback', @mousePressedCallback);
 
  % Set the mouse-press callback
  function mousePressedCallback(hTree, eventData) %,additionalVar)
  % if eventData.isMetaDown % right-click is like a Meta-button
  % if eventData.getClickCount==2 % how to detect double clicks
 
  % Get the clicked node
    clickX = eventData.getX;
    clickY = eventData.getY;
    treePath = jtree.getPathForLocation(clickX, clickY);
    % check if a node was clicked
    if ~isempty(treePath)
      % check if the checkbox was clicked
      if clickX <= (jtree.getPathBounds(treePath).x+iconWidth)
        node = treePath.getLastPathComponent;
        nodeValue = node.getValue;
        % as the value field is the selected/unselected flag,
        % we can also use it to only act on nodes with these values
        switch nodeValue
          case 'selected'
            node.setValue('unselected');
            node.setIcon(javaImage_unchecked);
            jtree.treeDidChange();
          case 'unselected'
            node.setValue('selected');
            node.setIcon(javaImage_checked);
            jtree.treeDidChange();
        end
      end
    end
  end % function mousePressedCallback
 
  function selected_cb( tree, ev )
    nodes = tree.getSelectedNodes;
    node = nodes(1);
    path = node2path(node);
  end
 
  function path = node2path(node)
    path = node.getPath;
    for i=1:length(path);
      p{i} = char(path(i).getName);
    end
    if length(p) > 1
      path = fullfile(p{:});
    else
      path = p{1};
    end
  end
 
  % add node
  function b1_cb( h, env )
    nodes = tree.getSelectedNodes;
    node = nodes(1);
    parent = node;
    childNode = uitreenode('v0','dummy', 'Child Node', [], 0);
    treeModel.insertNodeInto(childNode,parent,parent.getChildCount());
 
    % expand to show added child
    tree.setSelectedNode( childNode );
 
    % insure additional nodes are added to parent
    tree.setSelectedNode( parent );
  end
 
  % remove node
  function b2_cb( h, env )
    nodes = tree.getSelectedNodes;
    node = nodes(1);
    if ~node.isRoot
      nP = node.getPreviousSibling;
      nN = node.getNextSibling;
      if ~isempty( nN )
        tree.setSelectedNode( nN );
      elseif ~isempty( nP )
        tree.setSelectedNode( nP );
      else
        tree.setSelectedNode( node.getParent );
      end
      treeModel.removeNodeFromParent( node );
    end
  end
end % of main function treeExperiment6
 
  function [I,map] = checkedIcon()
    I = uint8(...
        [1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,0;
         2,2,2,2,2,2,2,2,2,2,2,2,2,0,0,1;
         2,2,2,2,2,2,2,2,2,2,2,2,0,2,3,1;
         2,2,1,1,1,1,1,1,1,1,1,0,2,2,3,1;
         2,2,1,1,1,1,1,1,1,1,0,1,2,2,3,1;
         2,2,1,1,1,1,1,1,1,0,1,1,2,2,3,1;
         2,2,1,1,1,1,1,1,0,0,1,1,2,2,3,1;
         2,2,1,0,0,1,1,0,0,1,1,1,2,2,3,1;
         2,2,1,1,0,0,0,0,1,1,1,1,2,2,3,1;
         2,2,1,1,0,0,0,0,1,1,1,1,2,2,3,1;
         2,2,1,1,1,0,0,1,1,1,1,1,2,2,3,1;
         2,2,1,1,1,0,1,1,1,1,1,1,2,2,3,1;
         2,2,1,1,1,1,1,1,1,1,1,1,2,2,3,1;
         2,2,2,2,2,2,2,2,2,2,2,2,2,2,3,1;
         2,2,2,2,2,2,2,2,2,2,2,2,2,2,3,1;
         1,3,3,3,3,3,3,3,3,3,3,3,3,3,3,1]);
     map = [0.023529,0.4902,0;
            1,1,1;
            0,0,0;
            0.50196,0.50196,0.50196;
            0.50196,0.50196,0.50196;
            0,0,0;
            0,0,0;
            0,0,0];
  end
 
  function [I,map] = uncheckedIcon()
     I = uint8(...
       [1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1;
        2,2,2,2,2,2,2,2,2,2,2,2,2,2,1,1;
        2,2,2,2,2,2,2,2,2,2,2,2,2,2,3,1;
        2,2,1,1,1,1,1,1,1,1,1,1,2,2,3,1;
        2,2,1,1,1,1,1,1,1,1,1,1,2,2,3,1;
        2,2,1,1,1,1,1,1,1,1,1,1,2,2,3,1;
        2,2,1,1,1,1,1,1,1,1,1,1,2,2,3,1;
        2,2,1,1,1,1,1,1,1,1,1,1,2,2,3,1;
        2,2,1,1,1,1,1,1,1,1,1,1,2,2,3,1;
        2,2,1,1,1,1,1,1,1,1,1,1,2,2,3,1;
        2,2,1,1,1,1,1,1,1,1,1,1,2,2,3,1;
        2,2,1,1,1,1,1,1,1,1,1,1,2,2,3,1;
        2,2,1,1,1,1,1,1,1,1,1,1,2,2,3,1;
        2,2,2,2,2,2,2,2,2,2,2,2,2,2,3,1;
        2,2,2,2,2,2,2,2,2,2,2,2,2,2,3,1;
        1,3,3,3,3,3,3,3,3,3,3,3,3,3,3,1]);
     map = ...
      [0.023529,0.4902,0;
       1,1,1;
       0,0,0;
       0.50196,0.50196,0.50196;
       0.50196,0.50196,0.50196;
       0,0,0;
       0,0,0;
       0,0,0];
  end

uitree with custom checkbox icons

uitree with custom checkbox icons

Custom Java classes

An alternative is to create a custom tree Java class and/or a custom TreeCellRenderer/TreeCellEditor. Specifically, to change the icons of each node you have to implement your own java component which derives from DefaultMutableTreeNode.

Some online resources to get you started:

Built-in classes

Another option is to use Matlab’s built-in classes, either com.mathworks.mwswing.checkboxtree.CheckBoxTree or com.jidesoft.swing.CheckBoxTree:

import com.mathworks.mwswing.checkboxtree.*
jRoot = DefaultCheckBoxNode('Root');
l1a = DefaultCheckBoxNode('Letters'); jRoot.add(l1a);
l1b = DefaultCheckBoxNode('Numbers'); jRoot.add(l1b);
l2a = DefaultCheckBoxNode('A'); l1a.add(l2a);
l2b = DefaultCheckBoxNode('b'); l1a.add(l2b);
l2c = DefaultCheckBoxNode('<html><b>&alpha;'); l1a.add(l2c);
l2d = DefaultCheckBoxNode('<html><i>&beta;'); l1a.add(l2d);
l2e = DefaultCheckBoxNode('3.1415'); l1b.add(l2e);
 
% Present the standard MJTree:
jTree = com.mathworks.mwswing.MJTree(jRoot);
jScrollPane = com.mathworks.mwswing.MJScrollPane(jTree);
[jComp,hc] = javacomponent(jScrollPane,[10,10,120,110],gcf);
 
% Now present the CheckBoxTree:
jCheckBoxTree = CheckBoxTree(jTree.getModel);
jScrollPane = com.mathworks.mwswing.MJScrollPane(jCheckBoxTree);
[jComp,hc] = javacomponent(jScrollPane,[150,10,120,110],gcf);

a regular MJTree (left) and a CheckBoxTree (right)

a regular MJTree (left) and a CheckBoxTree (right)

Note: Matlab’s CheckBoxTree does not have a separate data model. Instead, it relies on the base MJTree’s model, which is a DefaultTreeModel by default. JIDE’s CheckBoxTree does have its own model.

This concludes my uitree mini-series. If you have any special customizations, please post a comment below.

Customizing uitree nodes – part 1

Wednesday, August 25th, 2010

In my previous posts, I introduced the semi-documented uitree function that enables displaying data in a hierarchical (tree) control in Matlab GUI, and showed how it can be customized. Today, I will continue by describing how specific uitree nodes can be customized.

To start the discussion, let’s re-create last week’s simple uitree:

% Fruits
fruits = uitreenode('v0', 'Fruits', 'Fruits', [], false);
fruits.add(uitreenode('v0', 'Apple',  'Apple',  [], true));
fruits.add(uitreenode('v0', 'Pear',   'Pear',   [], true));
fruits.add(uitreenode('v0', 'Banana', 'Banana', [], true));
fruits.add(uitreenode('v0', 'Orange', 'Orange', [], true));
 
% Vegetables
veggies = uitreenode('v0', 'Veggies', 'Vegetables', [], false);
veggies.add(uitreenode('v0', 'Potato', 'Potato', [], true));
veggies.add(uitreenode('v0', 'Tomato', 'Tomato', [], true));
veggies.add(uitreenode('v0', 'Carrot', 'Carrot', [], true));
 
% Root node
root = uitreenode('v0', 'Food', 'Food', [], false);
root.add(veggies);
root.add(fruits);
 
% Tree
figure('pos',[300,300,150,150]);
mtree = uitree('v0', 'Root', root);

User-created tree    User-created tree

User-created tree

Labels

Node labels (descriptions) can be set using their Name property (the second uitreenode data argument). Note that the horizontal space allotted for displaying the node name will not change until the node is collapsed or expanded. So, if the new name requires more than the existing space, it will be displayed as something like “abc…”, until the node is expanded or collapsed.

Node names share the same HTML support feature as all Java Swing labels. Therefore, we can specify font size/face/color, bold, italic, underline, super-/sub-script etc.:

txt1 = '<html><b><u><i>abra</i></u>';
txt2 = '<font color="red"><sup>kadabra</html>';
node.setName([txt1,txt2]);

HTML-enriched tree nodes

HTML-enriched tree nodes

Icons

Tree-node icons can be specified during node creation, as the third data argument to uitreenode, which accepts an icon-path (a string):

iconPath = fullfile(matlabroot,'/toolbox/matlab/icons/greenarrowicon.gif');
node = uitreenode('v0',value,name,iconPath,isLeaf);

Tree node icons can also be created or modified programmatically in run-time, using Matlab’s im2java function. Icons can also be loaded from existing files as follows (real-life programs should check and possibly update jImage’s size to 16 pixels, before setting the node icon, otherwise the icon might get badly cropped; also note the tree-refreshing action):

jImage = java.awt.Toolkit.getDefaultToolkit.createImage(iconPath);
veggies.setIcon(jImage);
veggies.setIcon(im2java(imread(iconPath)));  % an alternative
 
% refresh the veggies node (and all its children)
mtree.reloadNode(veggies);

Setting node icon

Setting node icon

Behavior

Nodes can be modified from leaf (non-expandable) to parent behavior (=expandable) by setting their LeafNode property (a related property is AllowsChildren):

set(node,'LeafNode',false);  % =expandable
node.setLeafNode(0);  % an alternative

One of the questions I was asked was how to “disable” a specific tree node. One way would be to modify the tree’s ExpandFcn callback. Another way is to use a combination of HTML rendering and the node’s AllowsChildren property:

label = char(veggies.getName);
veggies.setName(['<html><font color="gray">' label]);
veggies.setAllowsChildren(false);
t.reloadNode(veggies);

Disabled node

Disabled node

Another possible behavioral customization is adding a context-menu to a uitree. We can set node-specific tooltips using similar means.

Answering a reader’s request from last week, tree nodes icons can be used to present checkboxes, radio buttons and other similar node-specific controls. This can actually be done in several ways, that will be explored in next week’s article.

There are numerous other possible customizations – if readers are interested, perhaps I will describe some of them in future articles. If you have any special request, please post a comment below.

Customizing uitree

Wednesday, August 18th, 2010

Last week, I introduced the semi-documented uitree function that enables displaying data in a hierarchical (tree) control in Matlab GUI.

Today, I will continue by describing how uitrees can be customized.

Note that although uitrees use Java objects internally, we can create and customize uitree using pure-Matlab code.

Creating non-standard tree types

To start the discussion, let’s create a simple uitree whose Root node is not one of the automatically-processed types (disk folder, GUI handle, or Simulink model). There are two ways of creating such a tree: active and reactive:

Actively building the tree

In this method, we actively create nodes and attach them to parent nodes when the tree is first built. For example:

% Fruits
fruits = uitreenode('v0', 'Fruits', 'Fruits', [], false);
fruits.add(uitreenode('v0', 'Apple',  'Apple',  [], true));
fruits.add(uitreenode('v0', 'Pear',   'Pear',   [], true));
fruits.add(uitreenode('v0', 'Banana', 'Banana', [], true));
fruits.add(uitreenode('v0', 'Orange', 'Orange', [], true));
 
% Vegetables
veggies = uitreenode('v0', 'Veggies', 'Vegetables', [], false);
veggies.add(uitreenode('v0', 'Potato', 'Potato', [], true));
veggies.add(uitreenode('v0', 'Tomato', 'Tomato', [], true));
veggies.add(uitreenode('v0', 'Carrot', 'Carrot', [], true));
 
% Root node
root = uitreenode('v0', 'Food', 'Food', [], false);
root.add(veggies);
root.add(fruits);
 
% Tree
figure('pos',[300,300,150,150]);
mtree = uitree('v0', 'Root', root);

The tree automatically display scrollbars if any of the presented tree-nodes requires more than the available tree space:

User-created tree    User-created tree

User-created tree

Reactively building the tree

In this method, also called “lazy loading”, we only create child nodes as a reaction to their parent node’s expansion. This is the method given in uitree’s semi-documented help section. The tree will initially display only the root node, and additional tree-nodes will be created as needed when the root or any of its child nodes is expanded.

For example (note how the data model is passed as an extra parameter to the ExpandFcn callback):

% Create the data
food.veggies = {'Potato','Tomato','Carrot'};
food.fruits = {'Apple','Pear','Banana','Orange'};
 
% Create the tree with an ExpandFcn  callback
root = uitreenode('v0', 'Food', 'Food', [], false);
figure('pos',[300,300,150,150]);
mtree = uitree('v0', 'Root',root, 'ExpandFcn',{@myExpandFcn,food});
 
% The following function should be added to Matlab's path:
function nodes = myExpandfcn(tree, value, model)
  try
    nodeIdx = 0;
    if strcmp(value,'Food')
      nodeNames = fieldnames(model);
      isLeaf = false;
    else
      nodeNames = model.(value);
      isLeaf = false;
    end
    for nodeIdx = 1 : length(nodeNames)
      nodeName = nodeNames{nodeIdx};
      nodes(nodeIdx) = uitreenode(nodeName,nodeName,[],isLeaf);
    end
  catch
    % never mind...
  end
  if isempty(nodeIdx) || nodeIdx == 0
      nodes = [];
  end
end

Resizing the tree

uitrees are created with a default position of (0,0), a width of 200 (or less if the figure is narrower) and a height spanning the entire figure’s content area. This can easily be modified following the tree’s creation using its Position property:

mtree = uitree(...);
mtree.Position = [100,100,50,150];  % modify position & size
mtree.Position(4) = 100;  % limit tree height to 100 pixels

Java-based customizations

Today’s article used pure Matlab code (or more precisely, Java code wrapped in pure Matlab). Many additional customizations are available at the JTree-level. The underlying jtree handle can easily be retrieved:

jtree = mtree.getTree;
jtree = get(mtree, 'tree');  % an alternative

As an example customization that uses jtree, consider one of my earliest articles on this website: Adding a context-menu to a uitree.

Interested readers might also benefit from looking at the tree manipulations that I have programmed in my FindJObj utility.

Next week’s article will conclude my uitree mini-series by describing how specific tree nodes can be customized. If you have any special customization request, please post a comment below.

The javacomponent function

Wednesday, August 4th, 2010

In this blog I have often showed how using Java components can significantly improve Matlab GUI. Here is a simple reminder:

sample Java components integrated in Matlab figure window (click for details)

sample Java components integrated in Matlab figure window (click for details)

Matlab is highly integrated with Java, and Java classes can seamlessly be accessed from Matlab. However, displaying Java GUI objects, as opposed to using computational (non-displayable) Java classes, requires using Matlab’s built-in javacomponent function. I have often used this function in past articles here, and today I would like to describe it in more detail.

javacomponent, available since R14 (Matlab 7.0), is yet another semi-documented built-in function. This means that the function is explained in a comment within the function (which can be seen via the edit(‘javacomponent’) command), but nonetheless does not have official help or doc pages. It is an unsupported function originally intended only for internal Matlab use (which of course doesn’t mean we can’t use it).

javacomponent accepts a component class name (a string) or a reference to a previously-created component object, an optional pixel position parameter (default=[20,20,60,20], just like uicontrol; may also contain the strings ‘North’, ‘South’, ‘East’ or ‘West’), and an optional parent container handle (defaults to the current figure). javacomponent then adds the requested component as a child of the requested parent container and wraps it in a Matlab Handle-Graphics (HG) container. javacomponent returns two handles: the Matlab HG container handle and a reference (handle) to the Java component. Here are some sample invocation formats:

>> [jButton, hButton] = javacomponent('javax.swing.JButton')
hButton =
	javahandle_withcallbacks.javax.swing.JButton
jButton =
          158.002197265625
 
>> javacomponent('javax.swing.JButton','North');
>> javacomponent(javax.swing.JButton('Click me!'),[50,40,80,30]);
>> javacomponent(javax.swing.JButton('Click me!'),'East',hFig);

Note the difference between Java object creation and javacomponent: A pre-created Java object only resides in JVM (Java Virtual Machine) memory, not onscreen, until javacomponent is called to display it. javacomponent only creates objects when a class name (string) parameter is passed to it, as a convenience service to programmers. In practice, it is better to separate these two actions: create the Java object separately, and then pass the object’s reference handle to javacomponent for display. This enables easier error-trapping if the Java object cannot be created or fails to initialize, before attempting to display the object:

% Create and initialize a JScrollBar object
try
   jScrollbar = javaObjectEDT('javax.swing.JScrollBar');
   jScrollbar.setOrientation(jScrollbar.HORIZONTAL);
catch
   error('Cannot create Java-based scroll-bar!');
end
% Display the object onscreen
try
   javacomponent(jScrollbar,'South');
catch
   error('Cannot display Java-base scroll-bar!');
end

Note that Java GUI object should always use the EDT (Event Dispatch Thread). The reasons for this were outlined in the recent Matlab-EDT article. For this reason, the JScrollBar is created using the built-in javaObjectEDT function, which exists since R2008a and became documented/supported in R2009a.

javacomponent accepts parent handles that are figures, toolbars, uipanels or uicontainers. Unfortunately, frames are not uicontainers and therefore cannot be used as javacomponent parents. Addendum Aug 6 2010: I made an incorrect statement in the original post here regarding uipanels, which has now been removed. I thank the reader who pointed this out to me.

Once the component has been created, even before it has been placed onscreen, it can be manipulated just like any other Java object. For example:

jButton.setText('Click again!');  % or: set(jButton,'text','…')

The component can also be manipulated to some extent via its HG container, which is of a special Matlab type (class) called hgjavacomponent. This includes getting/setting the component position, position units, visibility, resizing callback, tag, UserData etc:

set(hButton,'units','norm', 'position',[0.2,0.3,0.1,0.05]);
set(hButton,'visible','off'); %note: on/off, not true/false as in Java
set(hButton,'ResizeFcn',{@resizeCallbackFunc,param1,param2});

When adding Java components which are container classes (descendants of java.awt.Container), it is important to remember that only other Java components can be added to these containers. Matlab objects such as axes (for plots or images) and uicontrols cannot be added since they do not have a Container wrapper. Therefore, feel free to use these Java containers as long as their contained GUI is limited to Java components (JButton, JComboBox etc.). This limitation is very annoying – it would be very useful to be able to place Matlab axes or uicontrols within a JTabbedPane or JSplitPane. Instead, we need to rely on Matlab-based workarounds (uitab and uisplitpane) which are cumbersome compared to their Java counterparts.

javacomponent can be used to place not only Swing components but also Swing-extended components onscreen. Matlab itself almost never uses Swing components as-is, instead preferring to use MathWorks-derived extensions of these components, generally in the com.mathworks.mwswing or com.mathworks.widgets packages. These packages and their classes are all in the static Java classpath and are therefore automatically available for use by Matlab programmers.

Just like Matlab components, javacomponent can also display third-party or your own Swing-derived components. There are quite a few online sources for Swing components that can easily be incorporated in your Matlab application. Simply download the relevant class files, add them to your static (via classpath.txt) or dynamic (via javaaddpath) Java classpath, use javacomponent to display them, then use their reference handle to manipulate their appearance and behavior.

javacomponent, useful as it is, has several limitations. In its string variant (classname) it requires a fully-qualified classname that is not inferred automatically. It also has a different parameters format than uicontrol, which may confuse users. javacomponent also cannot display java.awt.Window components. Finally, it returns two handles – one is a handle() reference of the Java object; the second an HG handle (a double numeric value) of the automatically-created HG container – users are often confused as to which property should be set on which of these handles.

To overcome these limitations, I created UIComponent – a utility that merges uicontrol and javacomponent, available for download on the File Exchange. It accepts all uicontrol parameters and styles, as well as any other displayable Java (Swing/AWT) class. uicontrol’s calling syntax was preserved for full backwards compatibility. uicomponent uses the built-in uicontrol whenever possible (for standard Matlab styles), and javacomponent for all other Java classes.

uicomponent returns the same two handles that javacomponent returns (namely, a Java reference handle and a numeric HG handle), modified to include each other’s properties and handles (yet another undocumented trick that merits a dedicated article). Here are some examples (more can be found in uicomponent’s help comment):

uicomponent('style','edit', 'String','hello');  % a regular uicontrol
uicomponent(hFig, 'style','edit', 'String','hello'); % specify parent
uicomponent('style','jspinner','value',7);
uicomponent('style','javax.swing.jslider','tag','myObj'); 
uicomponent('style','JComboBox',{1,pi,'text'},'editable',true);

Another File Exchange submission which aims to tackle some of javacomponent’s limitations is Malcolm Lidierth’s JCONTROL. jcontrol uses Matlab’s new object-oriented class approach and has the benefit of returning just a single handle object, which aggregates the handles for both HG container and the contained Java object.

Matlab DDE support

Wednesday, July 21st, 2010

Windows DDE was a 1990’s technology used to transfer control between Windows applications. DDE was fully supported and documented in old Matlab releases (R13, R14). DDE is no longer documented in Matlab, although it apparently still works. In fact, Matlab says:
As of MATLAB version 5.1, all development work for the DDE Server and Client has been stopped and no further development will be done. The MathWorks strongly recommends that you migrate to the MATLAB interface to COM technology that is documented.

In the past decade, DDE has been superseded by newer Windows technologies deriving from COM, which is supported by Matlab. However, DDE is still used for some Windows infrastructure functions such as cut/copy/paste (CCP) and the Windows Shell file association. Today’s article, based on information given to me by Martin Höcker, a reader of this blog, uses this fact to interface the Windows Explorer with Matlab.

Martin works on an experiment that outputs a large number of small data files that have a “THe” extension. He wrote a Matlab script that parses and plots the data files individually. This script is called “THePlotter.m” and is on the Matlab path. But calling this script with the command “THePlotter(‘D:\Data\somedata.THe’)” in Matlab’s console is tedious, especially if we need to check hundreds of files.

Since all data files have the same “.THe” extension, Martin associated this file type with Matlab so double-clicking any file in Explorer will plot the data in Matlab. It is very easy to set this up using DDE:

  1. associate the “.THe” file type with Matlab as shown below (note: use the MATLAB.exe file in the /bin/win32 or /bin/win64 subfolder). Now Matlab will generate an error for a double-click on the file, but we don’t care.
    Associating an extension with Matlab (click for details)

    Associating an extension with Matlab (click for details)

  2. in Windows Explorer, click on Tools / Folder Options / File Types
  3. select the “.THe” extension and click “Advanced”
    Editing the file association details

    Editing the file association details

  4. set this to be the default action upon mouse double-click or keyboard ENTER
  5. select the “open” action, and click “Edit…”
  6. rename the action “plot” (renaming is optional) and click the “Use DDE” checkbox
  7. enter the DDE information as seen below:

Windows Explorer settings (click for details)

Windows Explorer settings (click for details)

It is even possible to have several “actions” for the file: Martin has “Plot”, and “Add to plot”, which allows plotting multiple files at once by simply choosing “Add to plot” with a right click in Windows Explorer:

Windows Explorer use (click for details)

Windows Explorer use (click for details)

Behind the scenes, all this is simply a GUI wrapper for adding/modifying the Windows Registry:

Registry entry for the Shell file association

Registry entry for the Shell file association

Note that despite some information in the R13/R14 documentation, we do not need to run Matlab with the /Automation startup flag (or any other special modification for that matter), at least in recent Matlab releases.

The biggest advantage of using DDE: It does not open up a new instance of Matlab whenever you click on a file. This saves an incredible amount of start-up time.

One thing we cannot do, is to pass parameter/value pairs to the “THePlotter” function. The problem possibly lies in the way that Matlab parses the DDE commands – the parameter is enclosed by quotes, and Matlab seems to turn these quotes into double-quotes, and then chokes on itself…

Have you found another neat trick to enhance your work-flow? If so, please share it in the comments section below, or send me an email

p.s.: Readers who are interested in using Matlab’s DDE functionality programmatically, are welcome to read and use the following semi-documented built-in functions: ddeadv, ddeexec, ddeinit, ddepoke, ddereq, ddeterm, ddeunadv. These functions have a readable help section, but no doc page nor official support.

Date selection components

Wednesday, June 30th, 2010

Have you ever wondered why Matlab does not have standard GUI date-handling components?

Matlab has many built-in date-handling functions (calendar, date, datestr, datenum, datetick, datevec etc.). Unfortunately, this built-in support does not extend to Matlab GUI. If we need a date-selection drop-down or calendar panel we have to design it ourselves, or use a third-party Java component or ActiveX control.

JIDE Components

Luckily, we have a much better alternative, right within Matlab. This relies on the undocumented fact that Matlab uses JIDE components for many of its GUI components. As already explained earlier, JIDE controls are pre-bundled in Matlab (/java/jarext/jide/jide-grids.jar under the Matlab root). You can find further details on JIDE Grids in the Developer Guide (pages 28-35) and the Javadoc documentation.

In particular, JIDE Grids includes the following date-selection controls:

  • DateChooserPanel – an extension of Swing’s JPanel that displays a single month and enables selecting one or more days
  • CalendarViewer – a similar panel, that displays several months in a table-format (e.g., 4×3 months)
  • DateComboBox – a combo-box (drop-down/popup menu) that presents a DateChooserPanel for selecting a date
  • DateSpinnerComboBox – presents a date-selection combo-box that includes both the DateComboBox and a spinner control (this control is only available in the latest Matlab releases)
  • MonthChooserPanel – a panel that enables selection of entire months (not specific dates)
  • MonthComboBox – a month selection combo-box, similar to DateComboBox but without the ability to select individual days

Usage of these controls is very similar, so I’ll just show the basics here. First, to present any control, we need to use the built-in javacomponent function or the uicomponent utility:

% Initialize JIDE's usage within Matlab
com.mathworks.mwswing.MJUtilities.initJIDE;
 
% Display a DateChooserPanel
jPanel = com.jidesoft.combobox.DateChooserPanel;
[hPanel,hContainer] = javacomponent(jPanel,[10,10,200,200],gcf)


DateChooserPanel   MonthChooserPanel

DateChooserPanel and MonthChooserPanel components

CalendarViewer

2x2 CalendarViewer component


Just as with any Java object, properties may either be accessed with the Java accessor methods (e.g. getName() or setName(name)), or the Matlab get/set semantics (e.g. get(prop,’Name’) or set(prop,’Name’,value)). When using the Matlab syntax, remember to wrap the Java object in a handle() call, to prevent a memory leak (or use hPanel rather than jPanel):

jPanel.setShowWeekNumbers(false);    % Java syntax
set(hPanel,'ShowTodayButton',true);  % Matlab syntax

Retrieving the selected date is easy:

>> selectedDate = jPanel.getSelectedDate()
selectedDate =
Sun Jun 27 00:00:00 IDT 2010
% or: selectedDate = get(jPanel,'SelectedDate');
 
% Note: selectedDate is a java.util.Date object:
>> selectedDate.get
	Class = [ (1 by 1) java.lang.Class array]
	Date = [27]
	Day = [0]
	Hours = [0]
	Minutes = [0]
	Month = [5]
	Seconds = [0]
	Time = [1.27759e+012]
	TimezoneOffset = [-180]
	Year = [110]

We can enable selection of multiple dates (SINGLE_SELECTION=0, SINGLE_INTERVAL_SELECTION=1,MULTIPLE_INTERVAL_SELECTION=2):

jModel = hPanel.getSelectionModel;  % a com.jidesoft.combobox.DefaultDateSelectionModel object
jModel.setSelectionMode(jModel.MULTIPLE_INTERVAL_SELECTION);
 
>> hPanel.getSelectionModel.getSelectedDates
ans =
java.util.Date[]:
    [java.util.Date]
    [java.util.Date]
    [java.util.Date]

And of course we can set a callback for whenever the user modifies the selected date(s):

hModel = handle(hPanel.getSelectionModel, 'CallbackProperties');
set(hPanel, 'ValueChangedCallback', @myCallbackFunction);

For the combo-box (drop-down/popup menus) controls, we obviously need to modify the displayed size (in the javacomponent call) to something much more compact, such as [10,10,100,20]. These components display one of the above panels as their pop-up selection panels. Users can access and customize these panels using the combo-box control’s getPopupPanel() function (or PopupPanel property).

DateComboBox   DateSpinnerComboBox

DateComboBox and DateSpinnerComboBox components

Numerous other customizations are possible with these JIDE components – have fun exploring (my uiinspect utility can be quite handy in this)! Just remember that JIDE evolves with Matlab, and so JIDE’s online documentation, which refers to the latest JIDE version, may be partially inapplicable if you use an old Matlab version. The older your Matlab, the more such inconsistencies that you may find.

Alternative components

There are several alternatives to the JIDE components:

If we have Matlab’s Financial toolbox, we can use the uicalendar function. Unfortunately, this control is not available if you don’t own the expensive Financial toolbox.

If we only target Windows-based platforms, we could use third-party ActiveXes such as the Microsoft Date-and-Time-Picker (MSComCtl2.DTPicker.2), Microsoft MonthView (MSComCtl2.MonthView.2) or the Microsoft Office Calendar (MSCAL.Calendar.7) ActiveX controls. Depending on your installed applications, you may have other similar controls. For example, if you have Symantec’s EndPoint Protection (SEP), you have access to the SEP Date Control (LDDATETIME.LDDateCtrl.1). Of course, these controls will not work on non-Windows platforms, or platforms that do not have these ActiveX controls installed.

We can also use other (non-JIDE) third-party Java controls from places like javashareware.com, swinglabs.org, downloadthat.com, sharewareconnection.com, easyfreeware.com, l2fprod.com, fileheap.com/software/components.html, swing-components.safe-install.com and many others. One specific example is NachoCalendar, from SourceForge.com.

Finally, we could use some of the utilities posted on the Matlab File Exchange: uical, uisetdate, calender (sic) and several others.

In my own biased opinion, none of these alternatives comes close to the ease-of-use and functionality of the JIDE components presented above. What do you think? Please add your comments here.

Advanced JIDE Property Grids

Wednesday, April 21st, 2010

Once again, I would like to welcome guest blogger Levente Hunyadi.

Non-standard property renderers and editors

Last week, I discussed JIDE’s property table and showed how we can add custom properties and present this table in our Matlab GUI. Today, I will extend the previous week’s example to include more sophisticated renderers and editors.

Cell renderers and editors are the backbone of JTable implementations, JIDE’s property grid included. Each property is associated with a type, and a renderer and an editor may be registered for a type. The cell renderer controls how the property value is displayed, while the editor determines how it is edited. For example, flags (Java Booleans) are often both rendered and edited using a checkbox, but can also use a text renderer with a combo-box editor. PropertyTable automatically assigns a default renderer and editor to each property, based on its type: Flags are assigned a combo-box editor of true/false values, and similarly for other types.

Let us now modify the preassigned editor. First, let’s set a checkbox editor (BooleanCheckBoxCellEditor) for flags and a spinner for numbers:

% Initialize JIDE's usage within Matlab
com.mathworks.mwswing.MJUtilities.initJIDE;
 
% Prepare the properties list:
% First two logical values (flags)
list = java.util.ArrayList();
prop1 = com.jidesoft.grid.DefaultProperty();
prop1.setName('mylogical');
prop1.setType(javaclass('logical'));
prop1.setValue(true);
list.add(prop1);
 
prop2 = com.jidesoft.grid.DefaultProperty();
prop2.setName('mycheckbox');
prop2.setType(javaclass('logical'));
prop2.setValue(true);
prop2.setEditorContext(com.jidesoft.grid.BooleanCheckBoxCellEditor.CONTEXT);
list.add(prop2);
 
% Now integers (note the different way to set property values):
prop3 = com.jidesoft.grid.DefaultProperty();
javatype = javaclass('int32');
set(prop3,'Name','myinteger','Type',javatype,'Value',int32(1));
list.add(prop3);
 
prop4 = com.jidesoft.grid.DefaultProperty();
set(prop4,'Name','myspinner','Type',javatype,'Value',int32(1));
set(prop4,'EditorContext',com.jidesoft.grid.SpinnerCellEditor.CONTEXT);
list.add(prop4);
 
% Prepare a properties table containing the list
model = com.jidesoft.grid.PropertyTableModel(list);
model.expandAll();
grid = com.jidesoft.grid.PropertyTable(model);
pane = com.jidesoft.grid.PropertyPane(grid);
 
% Display the properties pane onscreen
hFig = figure;
panel = uipanel(hFig);
javacomponent(pane, [0 0 200 200], panel);

A property grid with checkbox and spinner controls

A property grid with checkbox and spinner controls

Notice how the EditorContext is used to specify a non-standard renderer/editor for myspinner and mycheckbox: The mylogical flag displays as a string label, while mycheckbox displays as a checkbox; myinteger uses a regular integer editor that accepts whole numbers, while myspinner uses a spinner control to modify the value.

Note that instead of creating an entirely new properties list and table, we could have run last week’s example, modified list and then simply called model.refresh() to update the display.

Also note that Matlab types are automatically converted to Java types, but we must be careful that the results of the conversion should match our setType declaration. The logical value true converts to java.lang.Boolean, but 1 by default would be a double, which is the standard numeric type in Matlab. The int32 wrapper is needed to force a conversion to a java.lang.Integer.

Spinners with indefinite value bounds are seldom useful. The following shows how to register a new editor to restrict values to a fixed range. Remember to unregister the editor when it is no longer used:

javatype = javaclass('int32');
value  = int32(0);
minVal = int32(-2);
maxVal = int32(5);
step   = int32(1);
spinner = javax.swing.SpinnerNumberModel(value, minVal, maxVal, step);
editor = com.jidesoft.grid.SpinnerCellEditor(spinner);
context = com.jidesoft.grid.EditorContext('spinnereditor');
com.jidesoft.grid.CellEditorManager.registerEditor(javatype, editor, context);
 
prop = com.jidesoft.grid.DefaultProperty();
set(prop, 'Name','myspinner', 'Type',javatype, ...
          'Value',int32(1), 'EditorContext',context);
 
% [do something useful here...]
 
com.jidesoft.grid.CellEditorManager.unregisterEditor(javatype, context);

The principle is the same for combo-boxes:

javatype = javaclass('char', 1);
options = {'spring', 'summer', 'fall', 'winter'};
editor = com.jidesoft.grid.ListComboBoxCellEditor(options);
context = com.jidesoft.grid.EditorContext('comboboxeditor');
com.jidesoft.grid.CellEditorManager.registerEditor(javatype, editor, context);
 
prop = com.jidesoft.grid.DefaultProperty();
set(prop, 'Name','season', 'Type',javatype, ...
          'Value','spring', 'EditorContext',context);
 
% [do something useful here...]
 
com.jidesoft.grid.CellEditorManager.unregisterEditor(javatype, context);

A property grid with a combobox control

A property grid with a combobox control

Nested properties

Properties can act as a parent node for other properties. A typical example is an object’s dimensions: a parent node value may be edited as a 2-by-1 matrix, but width and height may also be exposed individually. Nested properties are created as regular properties. However, rather than adding them directly to a PropertyTableModel, they are added under a Property instance using its addChild method:

propdimensions = com.jidesoft.grid.DefaultProperty();
propdimensions.setName('dimensions');
propdimensions.setEditable(false);
 
propwidth = com.jidesoft.grid.DefaultProperty();
propwidth.setName('width');
propwidth.setType(javaclass('int32'));
propwidth.setValue(int32(100));
propdimensions.addChild(propwidth);
 
propheight = com.jidesoft.grid.DefaultProperty();
propheight.setName('height');
propheight.setType(javaclass('int32'));
propheight.setValue(int32(100));
propdimensions.addChild(propheight);

A property grid with nested property

A property grid with nested property

PropertyTableModel accesses properties in a hierarchical naming scheme. This means that the parts of nested properties are separated with a dot (.). In the above example, these two fully-qualified names are dimensions.width and dimensions.height.

Trapping property change events

Sometimes it is desirable to subscribe to the PropertyChange event. This event is fired by PropertyTableModel whenever any property value is updated. To expose Java events to Matlab, we use the two-parameter form of the handle function with the optional CallbackProperties parameter.

hModel = handle(model, 'CallbackProperties');
set(hModel, 'PropertyChangeCallback', @callback_onPropertyChange);

The callback function receives two input arguments: The first is the PropertyTableModel object that fired the event, the second is a PropertyChangeEvent object with properties PropertyName, OldValue and NewValue. The PropertyTableModel’s getProperty(PropertyName) method may be used to fetch the Property instance that has changed.

Callbacks enable property value validation: OldValue can be used to restore the original property value, if NewValue fails to meet some criteria that cannot be programmed into the cell editor. We may, for instance, set the property type to a string; then, in our callback function, use str2num as a validator to try to convert NewValue to a numeric matrix. If the conversion fails, we restore the OldValue:

function callback_onPropertyChange(model, event)
   string = event.getNewValue();
   [value, isvalid] = str2num(string); %#ok
   prop = model.getProperty(event.getPropertyName());
   if isvalid  % standardize value entered
      string = mat2str(value);
   else  % restore previous value
      string = event.getOldValue();
   end
   prop.setValue(string);
   model.refresh();  % refresh value onscreen

The JIDE packages that are pre-bundled in Matlab contain numerous other useful classes. Some of these will be described in future articles.

JIDE Property Grids

Wednesday, April 21st, 2010

I would like to welcome guest blogger Levente Hunyadi.

Matlab’s property inspector

We often wish to edit properties of heterogeneous objects using a common interface. Matlab’s property inspector, invoked with the built-in inspect function, answers this need. The inspector is based on a two-column table of property names and values. Properties and their values are populated automatically, and the user can edit values in-place. The inspector enables property categorization, sub-categorization and sorting, which help users find and modify properties easily. For each property, the inspector displays a matching edit control: editbox/combobox/checkbox etc. This simplifies property value editing and prevents illegal value entry. Matlab’s GUI builder, GUIDE, uses the inspector to let users edit GUI properties such as position, color etc. It is also used by other tools such as the Plot Editor.

Matlab's built-in property inspector

Matlab's built-in property inspector

The Matlab inspector can be embedded, with not-too-much effort, within Matlab GUI applications. Examples of this can be found in the FindJObj and UIInspect utilities.

FindJObj - embedded property inspector

FindJObj - embedded property inspector

Unfortunately, Matlab’s property inspector is limited to Handle Graphics, Java and COM objects, and cannot be used for structures or user-defined Matlab classes. We shall see below how to set up our own property grid, populate it with data, and subscribe to property change events. This is a rather procedural approach. It is usually more convenient to use a declarative approach in which a structure or Matlab class is passed to a function that automatically discovers its properties and their meta-information. The Property Grid utility at Matlab File Exchange provides these services.

A simple property grid

Matlab’s property inspector is based on a property grid control by JIDE Software. JIDE Grids is a collection of components that extend the standard Java Swing JTable component, and is included in each Matlab installation (/java/jarext/jide/jide-grids.jar under the Matlab root). In particular, JIDE Grids includes the PropertyTable class, which is a fully customizable property grid component. You can find further details on JIDE Grids in the Developer Guide and the Javadoc documentation.

There are several related classes associated with the PropertyTable class. First, a PropertyTableModel encapsulates all properties that are visualized in the property grid. Each property derives from the Property abstract class, which features some common actions to properties, most notably to get and set property value. DefaultProperty is a default concrete subclass of Property. Finally, PropertyPane decorates a property grid with icons for changing category view to alphabetically sorted view as well as expanding and collapsing categories, and a description text box at the bottom that can be shown or hidden.

Here are the DefaultProperty fields and their respective roles:

Field Role
Name Interal property name, not necessarily displayed, used as a key to identify the property.
DisplayName A short property name shown in the left column of the property grid.
Description A concise description of the property, shown at the bottom of the property pane, below the grid.
Type The Java type associated with the property, used to invoke the appropriate renderer or editor.
EditorContext An editor context object. If set, both the type and the context are used to look up the renderer or editor to use. This lets, for instance, one flag value to display as a true/false label, while another as a checkbox.
Category A string specifying the property’s category, for grouping purposes.
Editable Specifies whether the property value is modifiable or read-only.
Value The current property value, as a Java object.

Just as with any Java object, these fields may either be accessed with the Java get/set semantics (e.g. getName() or setName(name)), or the Matlab get/set semantics (e.g. get(prop,’Name’) or set(prop,’Name’,name)). When using the Matlab syntax, remember to wrap the Java object in a handle() call, to prevent a memory leak.

To use a property grid in Matlab, first construct a set of DefaultProperty objects. For each object, set at least the name, type and initial value. Next, add the properties to a table model. Finally, construct a property grid with the given table model and encapsulate in a property pane:

% Initialize JIDE's usage within Matlab
com.mathworks.mwswing.MJUtilities.initJIDE;
 
% Prepare the properties list
list = java.util.ArrayList();
prop1 = com.jidesoft.grid.DefaultProperty();
prop1.setName('stringProp');
prop1.setType(javaclass('char',1));
prop1.setValue('initial value');
prop1.setCategory('My Category');
prop1.setDisplayName('Editable string property');
prop1.setDescription('A concise description for my property.');
prop1.setEditable(true);
list.add(prop1);
 
prop2 = com.jidesoft.grid.DefaultProperty();
prop2.setName('flagProp');
prop2.setType(javaclass('logical'));
prop2.setValue(true);
prop2.setCategory('My Category');
prop2.setDisplayName('Read-only flag property');
prop2.setEditable(false);
list.add(prop2);
 
% Prepare a properties table containing the list
model = com.jidesoft.grid.PropertyTableModel(list);
model.expandAll();
grid = com.jidesoft.grid.PropertyTable(model);
pane = com.jidesoft.grid.PropertyPane(grid);
 
% Display the properties pane onscreen
hFig = figure;
panel = uipanel(hFig);
javacomponent(pane, [0 0 200 200], panel);
 
% Wait for figure window to close & display the prop value
uiwait(hFig);
disp(prop1.getValue());

Here, com.mathworks.mwswing.MJUtilities.initJIDE is called to initialize JIDE’s usage within Matlab. Without this call, we may see a JIDE warning message in some Matlab releases. We only need to initJIDE once per Matlab session, although there is no harm in repeated calls.

javaclass is a function (included in the Property Grid utility, or directly downloadable from here) that returns a Java class for the corresponding Matlab type with the given dimension: javaclass(‘logical’) or javaclass(‘logical’,0) (a single logical flag value) returns a java.lang.Boolean class; javaclass(‘char’,1) (a character array) returns a java.lang.String class; javaclass(‘double’,2) (a matrix of double-precision floating point values) returns double[][].

javacomponent is the undocumented built-in Matlab function that adds Java Swing components to a Matlab figure, using the given dimensions and parent handle. When the user closes the figure, prop.getValue() fetches and displays the new property value.

A simple user-defined property grid

A simple user-defined property grid

Next week’s article will show how to add more complex renderers and editors (display the flag value as a checkbox for example), define nested properties, and subscribe to property value change events. So stay tuned…

Plot LineSmoothing property

Wednesday, March 17th, 2010

I have already written about several undocumented hidden properties in the past. Today, I would like to introduce one of my favorites: the plot-line’s LineSmoothing property. Compare the following two outputs:

% Standard (non-smoothed) plot-line
plot(1:5,2:6,'o-', 'LineWidth',1);

Standard plot line (not anti-aliased)

Standard plot line (not anti-aliased)

% Smoothed (anti-aliased) plot line
plot(1:5,2:6,'o-', 'LineWidth',1, 'LineSmoothing','on');

Anti-aliased (smoothed) plot line

Anti-aliased (smoothed) plot line

Line smoothing (aka anti-aliasing) works by inserting semi-transparent pixels at the edges of the actual plot line, thereby giving an optical illusion of a smooth line without pixelization effects. In Matlab, antialiasing is done automatically for fonts, but unfortunately not for plot lines that have non-default line-widths.

Line-smoothing has been around for a long time. It was even mentioned in a user comment on the official MathWorks Pick-of-the-Week article that introduced the excellent Myaa utility (Myaa uses applicative Matlab code to create anti-aliased plot effects).

However, to this day (R2010a), the LineSmoothing property remains hidden, undocumented and not officially supported.

Perhaps the reason for this is the following bug: text objects that cross a smoothed line are obscured by it. Depending on the text size and the line width, the text might be completely hidden, although its handle indicates that it is visible and despite it being created after the plot line!

plot(1:5,2:6,'.-', 'LineWidth',5, 'LineSmoothing','on');
text(2.2,3.5, 'abcd','Color','r');

Smoothed line obscuring text

Smoothed line obscuring text

Note that this does not happen for standard (non-smoothed) lines:

plot(1:5,2:6,'.-', 'LineWidth',5);
text(2.2,3.5, 'abcd','Color','r');

Non-smoothed line does NOT obscure text

Non-smoothed line does NOT obscure text

Luckily, there’s a very simple workaround for this, that allows both line-smoothing and non-obstruction: simply set the text’s z-position to a higher value than the plot line’s. In our example, we used a simple 2D plot line (i.e., z-position = 0), so let’s set z-position=1 for our text label:

plot(1:5,2:6,'.-', 'LineWidth',5, 'LineSmoothing','on');
text(2.2,3.5,1, 'abcd','Color','r');

Smoothed line not obscuring text

Smoothed line not obscuring text

One final note: the LineSmoothing property also exists for line, patch, surf, mesh and other similar objects.

Do you use have any other favorite undocumented/hidden property? If so, please share it in a comment below.

Matlab and the Event Dispatch Thread (EDT)

Wednesday, March 10th, 2010

Once again I welcome guest blogger Matt Whitaker, with the long awaited EDT article.

Java Swing’s Event Dispatch Thread (EDT)
or: why does my GUI foul up?

Matlab for the most part is a single threaded environment. That is, all commands are executed sequentially along a single execution thread. The main exception to this are the Handle Graphics (GUI) components whose operations execute on the Java Event Dispatch Thread (EDT). EDT effects are reflected even in mundane Matlab GUI operations.

If we execute the code below we will probably see nothing until the loop completes and the figure appears with the text label showing ‘10000′:

h = figure;
txt = uicontrol('Parent',h, 'Style','text', 'String','1');
for n = 1:10000
    set(txt,'String',int2str(n))
end %for

By adding a couple of drawnow commands we get the figure and text label to render and then we see the count progress to 10000.

h = figure;
txt = uicontrol('Parent',h, 'Style','text', 'String','1');
drawnow;
for n = 1:10000
    set(txt,'String',int2str(n));
    drawnow;
end %for

The drawnow function allows the EDT queue to be flushed and the pending graphics operations to be evaluated. This will also happen with pause and several other commands.

If we want to use Swing (or AWT) components in our user interfaces we need to take this multi-threaded environment into account. The Swing toolkit designers decided to make all the Swing components thread un-safe in order to decrease their complexity. As a consequence, all access to Swing components should be done from the event dispatch thread (EDT), to ensure the operations are executed sequentially, at the exact order in which they were dispatched. Any action on a Swing component done on another thread (Matlab’s main processing thread in our case) risks a race-condition or deadlock with the EDT, which could (and often does) result in weird, non-deterministic and non-repetitive behavior – all of which should be avoided in any application which should behave in a precisely deterministic manner.

In Java, the usual pattern to accomplish EDT dispatching is to create a Runnable object, encapsulate the GUI code in the run method of the Runnable object, then pass the Runnable object to the static EventQueue.invokeLater (or EventQueue.invokeAndWait if we need to block operations to get a return value) method.

Runnable runnable = new Runnable()
{
    public void run()
    {
        //GUI Code here
    }
}
 
EventQueue.invokeLater(runnable);

There are several functions in Matlab that implement this programming pattern for us: javaObjectEDT, javaMethodEDT, awtinvoke, awtcreate and javacomponent. JavaMethodEDT and javaObjectEDT were introduced in version R2008b (7.7) and are minimally and only partially documented although they have reasonably complete help comments. The other three are semi-documented (meaning they are unsupported but if you edit or type their m-file you’ll see a fairly detailed help section), and although there is some overlap in their functionality they are still available.

javaObjectEDT and javaMethodEDT

javaObjectEDT is the the preferred method since R2008b of creating swing components to be used on the EDT. An object created with javaObjectEDT will have all of its subsequent method calls run on the EDT. This is termed Auto Delegation. Auto-delegation greatly simplifies and increases the readability of code. Note that objects created as a result of method calls may not be implemented on the EDT.

If you have an existing Java object, you can pass it to javaObjectEDT at any time – all its subsequent calls will then onward run on the EDT. Note that this useful functionality is an under-documented javaObjectEDT feature: it is not mentioned in the main help section but only implied from the example.

% Create a button on the EDT
btn = javaObjectEDT('javax.swing.JButton');
% this will run on EDT since btn was javaObjectEDT-created
btn.setText('Button');
 
% Create a button NOT on the EDT
btn2 = javax.swing.JButton;
% Dangerous! call will run on main Matlab thread
btn2.setText('Button2');
% modify btn2 so its methods will start running on the EDT
javaObjectEDT(btn2);
btn2.setText('Button2');

The following example shows the use of javaObjectEDT and javaMethodEDT in a more complex situation using a JTable:

function tableExample
hFig = figure;
drawnow; %need to get figure rendered
 
%use Yair's createTable to add a javax.swing.JTable
%http://www.mathworks.com/matlabcentral/fileexchange/14225-java-based-data-table
%wrap ceateTable in javaObjectEDT to put the ensuing method calls on the EDT
f = java.awt.Font(java.lang.String('Dialog'),java.awt.Font.PLAIN,14);
headers = {'Selected','File','Analysis Routine','Task Status'};
tbl = javaObjectEDT(createTable(hFig,headers,[],false,'Font',f));
 
%set column 1 to use check boxes and set up a change callback
tbl.setCheckBoxEditor(1);
jtable = javaObjectEDT(tbl.getTable); %get the underlying Java Table. IMPORTANT: we need to put jtable on the EDT
columnModel = javaObjectEDT(jtable.getColumnModel); %now we can now do direct calls safely on jtable
selectColumn = javaObjectEDT(columnModel.getColumn(0));
selectColumnCellEditor = selectColumn.getCellEditor;
chk = javaMethodEDT('getComponent',selectColumnCellEditor);
set(chk,'ItemStateChangedCallback',@chkChange_Callback);
 
%make column three a combo drop down
analysisTable = {'Analysis1';'Analysis2';'Analysis3'};
cb = javaObjectEDT('com.mathworks.mwswing.MJComboBox',analysisTable);
cb.setEditable(false);
cb.setFont(f);
set(cb,'ItemStateChangedCallback',@cbChange_Callback);
editor = javaObjectEDT('javax.swing.DefaultCellEditor',cb);
analysisColumn = javaObjectEDT(columnModel.getColumn(2));
analysisColumn.setCellEditor(editor);
 
%set some column with restrictions
selectColumn.setMaxWidth(100);
analysisColumn.setPreferredWidth(300);
 
%set the data
SELECTED = java.awt.event.ItemEvent.SELECTED;
tbl.setData({false,'file1','Analysis2','Analysis2';...
             true,'file2','Analysis3','Analysis3'});
drawnow;
 
    function cbChange_Callback(src,ev) %#ok
        jRow = jtable.getSelectedRow;
        stateChange = javaMethodEDT('getStateChange',ev);
        if stateChange == SELECTED
            newData = javaMethodEDT('getItem',ev);
            model = jtable.getModel;
            javaMethodEDT('setValueAt',model,newData,jRow,3);
        end %if
    end %cbChange
 
    function chkChange_Callback(src,ev) %#ok
        chkBox = javaMethodEDT('getItem',ev);
        if logical(javaMethodEDT('isSelected',chkBox))
            beep; %put useful code here
        else
            beep;
            pause(0.1)
            beep; %put useful code here
        end %if
    end %chkChange_Callback
 
end %tableExample

If you are running Matlab R2008a or later, javacomponent uses the javaObjectEDT function to create the returned objects so you do not have to do anything further to these objects to have their calls dispatched on the EDT. Users need to take care that objects added directly to the components created by javacomponent are on the EDT as well as specialized sub-components (e.g. CellRenderers and CellEditors). The overhead of calling javaMethodEDT is fairly small so if in doubt, use it.

javaObjectEDT and its kin first appeared in R2008a, although they only became supported in R2008b. Unfortunately, using them on R2008a sometimes causes hangs and all sorts of other mis-behaviors. This problem was fixed in the R2008b release, when javaObjectEDT became a fully-supported function. The problem with using javaObjectEDT in our application is that if it ever runs on an R2008a platform it might hang! (on Matlab release R2007b and earlier we will get an informative message saying that the javaObjectEDT function does not exist)

For this reason, I am using the following method in my projects:

function result = javaObjEDT(varargin)
%Placeholder of Matlab's buggy javaObjectEDT function on R2008a
 
% Programmed by Yair M. Altman: altmany(at)gmail.com
% $Revision: 1.2 $  $Date: 2009/01/25 11:31:08 $
 
  try
      try
          result = varargin{1};
      catch
          result = [];
      end
      v = version;
      if str2double(v(1:3)) > 7.6
          result = builtin('javaObjectEDT',varargin{:});
      end
  catch
      % never mind
  end
end

Note that javaMethodEDT has the method name as its first input argument, and the object name or reference as its second arg. This is inconsistent with many other Matlab/Java functions, which normally accept the target object as the first argument (compare: invoke, awtinvoke, notify etc.). It also means that we cannot use the familiar obj.javaMethodEDT(methodName) format.

One final note: when javaObjectEDT and javaMethodEDT first appeared in R2008a, they were complemented by the javaObjectMT and javaMethodMT functions, which create and delegate Java objects on the main Matlab computational thread. Their internal documentation says that there are cases when execution must occur on the MT rather than EDT, although I am personally not aware of any such case.

awtcreate and awtinvoke

For users with versions prior to R2008b the user must use the awtcreate function to create objects on the EDT. One huge disadvantage of this older function is that if you have to pass java objects in the parameter list you must use the very cumbersome JNI style notation. For example, for the simple task of setting a button label, one has to use:

btn = awtcreate('javax.swing.JButton');
awtinvoke(btn,'setText(Ljava/lang/String;)','click me')

The other disadvantage is that creating the object using awtcreate does not ensure that its subsequent method calls will be executed on the EDT. The awtinvoke function must be used for each call.

Also, both awtcreate and awtinvoke have some limitations due to bugs in the private parseJavaSignature function (for example, invoking methods which accept a java.lang.Object) which forces one to use the direct call to the method, using the main Matlab thread. This can result in the undesired effects described above. In this situation the best workaround is to call pause(0.01) to allow the event queue to clear.

Versions of javacomponent earlier than R2008a use awtcreate and objects created by these versions must have their subsequent methods called by awtinvoke to be used on the EDT.

A very rare CSSM thread discusses the usage of awtcreate and awtinvoke with some very interesting remarks by MathWorks personnel.

There is an interesting option in awtinvoke that was not carried over into the newer javaMethodEDT. This option allows the user to pass a function handle in the argument list along with its parameters. This option creates an undocumented com.mathworks.jmi.Callback object that has a delayed callback. The delayed callback is dispatched on the EDT so that it will be called once the java method used in awtinvoke is finished. Note that the actual function will still execute on the main Matlab thread the delayed callback will just control when it is called. However this may be useful at times. It is possible to put this functionality into a separate function we can call to delay execution until the event queue is cleared.

%CALLBACKONEDTQUEUE will place a callback on the EDT to asynchronously
%run a function.
%CALLBBACKONEDTQUEUE(FCN) will run function handle FCN once all previous
%methods dispatched to the EDT have completed.
%CALLBBACKONEDTQUEUE(FCN,ARG1,ARG2,...) ill run function handle FCN with
%arguments ARG1,ARG2...once all previous methods dispatched to the EDT
%have completed.
%Note that the function is still executing on the main Matlab thread. This
%function just delays when it will be called.
function callbackOnEDTQueue(varargin)
    validateattributes(varargin{1},{'function_handle'},{});
    callbackObj = handle(com.mathworks.jmi.Callback,'callbackProperties');
    set(callbackObj,'delayedCallback',{@cbEval,varargin(:)});
    callbackObj.postCallback;
 
    function cbEval(src,evt,args) %#ok
        feval(args{:});
    end %cbEval
end %callbackOnEDTQueue