Archive for the ‘Java’ 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.

uitree

Wednesday, August 11th, 2010

Can you guess which built-in Matlab function is the top search-term on UndocumentedMatlab.com and yet one of the least discussed topic on the CSSM forum?

The answer is uitree – Matlab’s built-in function for displaying data in a hierarchical (tree) GUI component. uitree has been included in all Matlab 7 releases, but has never been officially supported. Like most other uitools in the %matlabroot%/toolbox/matlab/uitools/ folder, uitree and its companion uitreenode are semi-documented, meaning that they have no support or doc-page, but do have readable help sections within their m-files. In our case, edit the uitree.m and uitreenode.m files to see their help section.

Note the following comment within %matlabroot%/toolbox/local/hgrc.m, which implies that uitree may soon become fully supported, although its interface might change somewhat (as was the case when uitable became supported in R2008a):
Temporarily turn off old uitree and uitreenode deprecated function warning… When we introduce the new documented uitree to replace the old undocumented uitree …

Like most other uitools (e.g. uitable and uitab), uitree is based on an underlying Java component, which ultimately extends Swing’s standard JTree. uitree sets up a scrollable JTree on-screen without the hassle of setting up a scrollable viewport and other similar nuts and bolts. In fact, you don’t need to know any Java to use uitree (although knowing JTree can greatly help you customize it) – uitrees can be manipulated using pure Matlab code, as shall be seen below.

uitree accepts an optional figure handle followed by P-V (property-value) pairs. Settable properties are Root, ExpandFcn, SelectionChangeFcn, Position (also Parent, but read on). As in uitab, a ‘v0′ input argument may be necessary to suppress a warning message. Note that uitrees are always created as a direct child of the containing figure, ignoring creation-time Parent values. However, the Parent property can be modified following the tree’s creation:

[mtree, container] = uitree('v0', 'Root','C:\', 'Parent',hPanel); % Parent is ignored
set(container, 'Parent', hPanel);  % fix the uitree Parent

A simple uitree

A simple uitree

uitree returns two arguments: a handle to the created tree (a Java object wrapped within a Matlab handle) and an entirely-undocumented second optional argument holding a handle to the Matlab GUI container of the created tree. These two arguments are exactly the two arguments returned from the javacomponent function that I described last week.

uitreenode

uitree automatically understands Root objects of type Handle Graphics, Simulink model or char string (interpreted as a file-system folder name). Other Root types require setting dedicated ExpandFcn, SelectionChangeFcn Matlab callbacks (see uitree’s help section or below for examples).

If we need to create a custom tree hierarchy (i.e., our root node is not an HG object, Simulink model or folder name), then we need to use the semi-documented uitreenode function as follows:

node = uitreenode('v0',handle(mtree),'my root','c:\root.gif',false);
mtree.setRoot(node);
set(mtree,'Root',node);  % alternative to mtree.setRoot()

uitreenode accepts 4 arguments: a string or handle value (the node’s “internal” value), a string description (shown next to the node’s icon), an icon filename ([] will result in an icon assigned based on the node value), and a flag indicating whether the node is a leaf (no children) or not.

uitreenode returns a node object, which is little more than a Matlab handle wrapper for a Java Swing DefaultMutableTreeNode.

Node manipulation

Nodes can be added, moved or removed by node methods: node.add(anotherNode) adds anotherNode to the end of this node’s children list (possibly detaching it from its previous parent); node.insert(anotherNode,index) does the same but inserts anotherNode at a specific child index, rather than at the end; node.clone() makes a duplicate of this node that can then be added to another node; node.remove(index) and node.remove(node) remove a specific node whereas node.removeFromParent() removes this node; node.removeAllChildren() removes all children, if any, of this node.

Nodes can also be added and removed at the tree level: mtree.add(parent,nodes) allows adding a list of nodes to a parent node and mtree.remove(nodes) removes the specified nodes.

In order to programmatically collapse and expand nodes, use mtree.collapse(node) and mtree.expand(node).

Nodes can be programmatically selected using mtree.setSelectedNode(node). Multiple nodes may be selected using mtree.setSelectedNodes, if an earlier call to mtree.setMultipleSelectionEnabled(true) was made (default is multiple-selection disabled):

mtree.setSelectedNode(root);  % root is a node
mtree.setSelectedNodes([root,node1,node2]);  % select 3 nodes

programmatically selecting multiple tree nodes

programmatically selecting multiple tree nodes

The currently-selected node(s) can be accessed using mtree.getSelectedNodes. Node selection callbacks often require knowledge of the currently selected rows:

% Tree set up
mtree = uitree(..., 'SelectionChangeFcn',@mySelectFcn);
set(mtree, 'SelectionChangeFcn',@mySelectFcn); % an alternative
 
% The tree-node selection callback
function nodes = mySelectFcn(tree, value)
    selectedNodes = tree.getSelectedNodes;
    if ~isempty(selectedNodes)
        % ...
    end
end  % mySelectFcn

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

Next week’s article will show how uitrees can be customized. There are numerous possible customizations, including icons, labels, appearance, and behavior. So if you have any special 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.

Syntax highlighted labels & panels

Wednesday, July 14th, 2010

A few weeks ago, a reader of my article about rich Matlab editbox contents asked whether it is possible to display syntax-highlighted contents, i.e. contents whose color changes based on its underlying text, often called syntax hilite in affection. I gave a very specific answer in a reply comment, which I expand in today’s full-length article.

Matlab has two built-in Java classes that can present syntax-highlighted text: SyntaxTextLabel presents single-line labels, while SyntaxTextPane presents a multi-line editor pane. Both of these classes support C, HTML/XML, Java and Matlab syntax highlighting, as well as standard plaint-text. Some related JIDE classes are also described.

SyntaxTextLabel

SyntaxTextLabel is used to display a syntax-highlighted single-line text label according to the specified programming language: C_STYLE, HTML_STYLE, JAVA_STYLE, PLAIN_STYLE and of course M_STYLE for Matlab code:

str = 'for id=1:3, set(h(id),''string'',num2str(id)); end  % Matlab code';
codeType = com.mathworks.widgets.SyntaxTextLabel.M_STYLE;
jCodeLabel = com.mathworks.widgets.SyntaxTextLabel(str,codeType)
[jhLabel,hContainer] = javacomponent(jCodeLabel,[10,10,300,20],gcf);

SyntaxTextLabels (different code styles)

SyntaxTextLabels (different code styles)

StyledLabel

More flexibility in the displayed label styles can be achieved with HTML/CSS, and the bundled JIDE class com.jidesoft.swing.StyledLabel provides even more flexibility:

import java.awt.*
import com.jidesoft.swing.*
str = 'Mixed Underlined Strikethrough Super and Subscript combo Styles';
com.mathworks.mwswing.MJUtilities.initJIDE;
jStyledLabel = StyledLabel(str); 
styles = [StyleRange(0,5,  Font.BOLD,   Color.BLUE), ...
          StyleRange(6,10, Font.PLAIN,StyleRange.STYLE_UNDERLINED),...
          StyleRange(17,13,Font.PLAIN,  Color.RED,   ...
                           StyleRange.STYLE_STRIKE_THROUGH), ...
          StyleRange(31,5, Font.PLAIN,  Color.BLUE,  ...
                           StyleRange.STYLE_SUPERSCRIPT), ...
          StyleRange(37,3, Font.ITALIC, Color.BLACK), ...
          StyleRange(41,9, Font.PLAIN,  Color.BLUE,  ...
                           StyleRange.STYLE_SUBSCRIPT), ...
          StyleRange(51,5, Font.PLAIN,  StyleRange.STYLE_WAVED + ...
                           StyleRange.STYLE_STRIKE_THROUGH)];
jStyledLabel.setStyleRanges(styles);
[jhLabel,hContainer] = javacomponent(jStyledLabel,[10,10,300,20],gcf);

JIDE StyledLabel (different font styles)

JIDE StyledLabel (different font styles)

StyledLabels have subclasses that can be used to present styled text in tables, trees or lists. JIDE also provides the convenient StyledLabelBuilder, which enables easy multi-style text construction.

Finally, JIDE provides the ClickThroughStyledLabel, a StyledLabel extension that allows setting a target component, so that mouse clicks on the label will actually trigger the target component. This can be useful in forms where components have adjacent descriptive labels.

SyntaxTextPane

Multi-line syntax-highlighted code can be displayed with Matlab’s SyntaxTextPane class. SyntaxTextPane uses MIME types rather than styles for syntax-highlighting, but the end-result appears similar:

jCodePane = com.mathworks.widgets.SyntaxTextPane;
codeType = jCodePane.M_MIME_TYPE;  % ='text/m-MATLAB'
jCodePane.setContentType(codeType)
str = ['% create a file for output\n' ...
       '!touch testFile.txt\n' ...
       'fid = fopen(''testFile.txt'', ''w'');\n' ...
       'for i=1:10\n' ...
       '    % Unterminated string:\n' ...
       '    fprintf(fid,''%6.2f \\n, i);\n' ...
       'end'];
str = sprintf(strrep(str,'%','%%'));
jCodePane.setText(str)
jScrollPane = com.mathworks.mwswing.MJScrollPane(jCodePane);
[jhPanel,hContainer] = javacomponent(jScrollPane,[10,10,300,100],gcf);

SyntaxTextPane panel (Matlab MIME type)

SyntaxTextPane panel (Matlab MIME type)

The nice thing about SyntaxTextPane is that it syntax-highlights on-the-fly as you type or edit in the SyntaxTextPane (assuming you have not disabled editing with the setEditable(flag) method). This is exactly the behavior we have come to expect in the full-blown Matlab editor, and can now be embedded as a simple panel within our GUI.

Despite its misleadingly-simple look, SyntaxTextPane actually has most capabilities of the full-blown editor, not just syntax highlighting. This includes multiple undo/redo actions; smart indentation/commenting; automatic indication of corresponding block elements (if-end, for-end, etc. – also known as delimiter matching); search/replace, drag-and-drop and cut-copy-paste support; and many more.

Interested readers can use the uiinspect and checkClass utilities to explore the full capabilities offered by SyntaxTextPane. In this respect it would be helpful to also look at its super-class (SyntaxTextPaneBase) and the related SyntaxTextPaneUtilities class.

Summary

These Java classes are examples of built-in classes that can be used in Matlab applications, enabling a much richer GUI experience than possible using the standard (documented/supported) Matlab widgets.

As I have shown above, using these classes is extremely easy, and requires absolutely no Java knowledge. On the flip side, these internal Matlab classes may easily break in any future Matlab release, so be extra careful when deciding to use them. Future articles in this website will describe other similarly-useful built-in classes.

Have you found any other useful built-in Matlab class? If so, please post a comment.

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.

Tab panels – uitab and relatives

Wednesday, June 23rd, 2010

In the past year, readers of this blog have used its search box thousands of times. Can you guess what the top search terms are?

It turns out that 7 of the top 15 search terms relate to tables, trees and tab-panes.

These items are related in being standard GUI elements that unfortunately have very lacking support in Matlab. They all have corresponding functions in the %matlabroot%/toolbox/matlab/uitools folder, which was already introduced here as containing many unsupported GUI functions. Specifically, uitable for tables (this became supported in R2008a, but even the supported version has many important undocumented aspects); uitree and uitreenode for trees; and uitab and uitabgroup for tab-panes, which are today’s subject. Future articles will describe tables, trees and tab-panes in more detail.

uitab & uitabgroup

Like most other uitools, the uitab and uitabgroup functions are semi-documented, meaning that they have no support or doc-page, but do have readable help sections within their m-files. In our case, edit the uitab.m and uitabgroup.m files to see their help section.

Available since 2004 (R14 SP2, aka 7.0.4), Matlab’s uitabgroup uses the Matlab Java widget com.mathworks.hg.peer.UITabGroupPeer, which extends the standard javax.swing.JTabbedPane. Unlike uitable and uitree, which use actual Java objects to both store and present the data, uitabgroup only sets up the Java object to display the tabs, whereas the tab contents themselves are placed in entirely unrelated Matlab uicontainers. Matlab uses very clever double-booking to keep the Java and Matlab objects synchronized. The ability to “switch” tabs is actually a deception: in reality, a listener placed on the SelectedIndex property of the tab group causes the relevant Matlab container to display and all the rest to become hidden. Other listeners control containers’ position and size based on the tab group’s. Adding and removing tabs uses similar methods to add/remove empty tabs to the JTabbedPane. Read uitabgroup’s schema.m for details.

A drawback of this complex mechanism is the absence of a single customizable Java object. The benefit is that it allows us to place any Matlab content within the tabs, including plot axes which cannot be added to Java containers. Had uitabgroup been a Java container, we could not add axes plots or images to its tabs. In my humble opinion, Matlab’s tab implementation is an ingenious piece of engineering.

Here’s a simple tab-group adapted from uitabgroup’s help section:

hTabGroup = uitabgroup; drawnow;
tab1 = uitab(hTabGroup, 'title','Panel 1');
a = axes('parent', tab1); surf(peaks);
tab2 = uitab(hTabGroup, 'title','Panel 2');
uicontrol(tab2, 'String','Close', 'Callback','close(gcbf)');

(recent Matlab releases throw a warning when using this code: either add the ‘v0′ input arg to uitabgroup and uitab calls, or suppress the MATLAB:uitabgroup:MigratingFunction warning)

Here, the returned uitabgroup object hTabGroup is actually a Matlab container (deriving from uiflowcontainer) that always displays two elements: the Java tab-group, and the active Matlab uicontainer (the active tab’s contents). Understanding this, hTabGroup’s FlowDirection property becomes clear. However, it is better to use hTabGroup’s TabLocation property, which accepts ‘top’, ‘bottom’, ‘left’ and ‘right’:

TabLocation = 'top'

TabLocation = 'top'

TabLocation = 'left'

TabLocation = 'left'

Another hTabGroup property of interest is Margin, which sets the margin in pixels before each of the displayed elements – not just between them as might be expected: Increasing Margin (default=2 pixels) increases the gap between the tab group and the active tab’s contents, but also the gap between the tab group and figure edge:

TabLocation = 'bottom', Margin = 20   TabLocation = 'left', Margin = 20

Margin = 20

Tabs can be selected programmatically, by setting hTabGroup’s SelectedIndex property. Reading this property is useful when setting tab-selection callbacks using the SelectionChangeFcn property:

set(hTabGroup,'SelectionChangeFcn',@myCallbackFcn);
set(hTabGroup,'SelectedIndex',2);   % activate second tab

(R2010b pre-release documentation has some incorrect information about this, which I have reported. Unfortunately, I cannot disclose any additional details here since usage of the pre-release implies an NDA. When the official release is made, I will update this post accordingly).

Additional control over the tab group’s behavior can be achieved by customizing the underlying Java object. This object is not directly exposed by uitabgroup, but can be found using the FindJObj utility or via the hidden ApplicationData. Remember that Java objects use 0-based indexing so tab #1 is actually the second tab. Also remember that HTML is accepted just as in any other Swing-based label:

% Get the underlying Java reference using FindJObj
jTabGroup = findjobj('class','tabgroup');
 
% A direct alternative for getting jTabGroup
jTabGroup = getappdata(handle(hTabGroup),'JTabbedPane');
 
% Now use the Java reference to set the title, tooltip etc.
jTabGroup.setTitleAt(1,'Tab #2');
jTabGroup.setTitleAt(1,'<html><b><i><font size=+2>Tab #2');
jTabGroup.setToolTipTextAt(1,'Tab #2');
 
% Disabling tabs can only be done using the Java handle:
jTabGroup.setEnabledAt(1,0);  % disable only tab #1 (=2nd tab)
jTabGroup.setEnabled(false);  % disable all tabs

A future post will describe tab customization, including fonts, colors, icons and even addition of close buttons as in modern web browsers.

tabdlg

tabdlg is a related semi-documented and unsupported uitool that, like uitabgroup, creates a tabbed user interface. However, unlike uitabgroup, tabdlg uses plain-vanilla Matlab, without reliance on Java (well, actually all Matlab GUI controls ultimately rely on Java, but tabdlg does not use any Java beyond that). The end result looks less professional than uitabgroup, but it works even when Java does not.

tabdlg has an extensive help section, so it will not be detailed here. In brief, the input parameters specify the tab labels, dimensions, offsets, callbacks, font, default tab, sheet dimensions and parent figure. Here is a sample usage, taken from tabdlg’s help section. This code is executed whenever tabdlg is invoked without any input arguments:

tabdlg left tab

tabdlg left tab

tabdlg right tab

tabdlg right tab

File Exchange alternatives

There are many implementations of tab panels in the Matlab File Exchange. Matlab’s official Desktop Blog had an article about one specific example, which was that week’s Peek of the Week, and relied on adjacent buttons that are easy to implement, but in my personal opinion are a far cry from our expectations of a tab panel.

Better FEX utilities are: Multiple Tab GUI, Highlight Tab Objects easily, and best of all: uitabpanel or TabPanel Constructor.

Another very recent submission was this week’s POTW. This utility gives a professional (although somewhat non-standard) look, and is very easy to program – an excellent utility indeed.

All of the numerous tab-panel FEX utilities, as well as the fact that tab-panels are one of the most searched-for terms in this website, indicate the Matlab community’s desire to have supported native-looking tab-panel GUI in Matlab. Perhaps after 6 years it is time to bring uitab and uitabgroup into the light?

JMI wrapper – remote MatlabControl

Wednesday, May 26th, 2010

Perhaps the most difficult aspect of Matlab-Java integration is JMI (Java-to-Matlab Integration) over a remote connection, meaning a Java program that communicates with a separate Matlab process. Once again I welcome guest blogger Joshua Kaplan, who concludes his series of JMI-related articles with the awaited holy grail on this topic.

Remote control of Matlab

Last week I demonstrated using matlabcontrol to call Matlab from Java from within the Matlab application. Today I will explain how to control Matlab from a remote Java session. We will create a small Java program that allows us to launch and connect to Matlab, then send it eval commands and receive the results. While this example will involve creating a dedicated user interface, matlabcontrol can be integrated into any existing Java program without requiring any user interface.

matlabcontrol was originally created for controlling Matlab, not for performing computations. If your exclusive concern is to perform Matlab computations and use the results in Java, then check the Matlab Builder JA toolbox, which is made by MathWorks and is officially supported. Unfortunately this toolbox is quite expensive and does not enable interaction with a running Matlab session (it uses the non-GUI Matlab engine, much as the compiler does). It is for this purpose that the open-source (free) matlabcontrol package was created.

Note that matlabcontrol opens a new running Matlab session and does not connect to an already-running session. Matlab commands can then be invoked either interactively (in Matlab’s Command Window) or remotely (from Java). Debugging an already-open Matlab session can be done with jdb over a dedicated port, using an altogether different mechanism than matlabcontrol – this will be discussed in a future post.

Matlab has documented support for a COM interface (Windows) and process pipes (Unix/Mac) that allow remote communication from external applications. Unfortunately Java does not natively support COM, which is where matlabcontrol helps using its RMI approach. Interested readers can also try using a Java/COM bridge (JACOB or JCOM) as an alternative that would have the added benefits of enabling communication with an existing Matlab session and of MathWorks’ documented support.

A simple RemoteExample

Today’s RemoteExample demo is too long to paste into this post; instead you can download the source code, or a jar file that contains both the pre-compiled classes and matlabcontrol. To run this jar on Windows or Mac OS X you only need to double click on it (if you are running on Linux I’m sure you know what to do…). If you wish to download and compile the source file, remember that you will need the matlabcontrol jar referenced in your Java classpath.

Let’s dive in: The file begins with the mainline followed by default sizes and status messages. The user interface is then built using standard Swing components – there’s nothing special here, just some panels, panes, text fields, buttons, etc.

The interesting part begins when the RemoteMatlabProxyFactory object is created:

RemoteMatlabProxyFactory factory = new RemoteMatlabProxyFactory();

This Matlab-proxy factory object is used when the user clicks the “Connect” button:

factory.requestProxy();

This creates a RemoteMatlabProxy object. RemoteMatlabProxys must be created by a RemoteMatlabProxyFactory and cannot be directly constructed. When requestProxy() is called, matlabcontrol launches Matlab and connects to it using RMI. When the connection is established, a MatlabConnectionListener added to the factory will be notified using its connectionEstablished(RemoteMatlabProxy proxy) callback method. The RemoteMatlabProxy object passed into this method is now connected to Matlab.

Connecting Java to Matlab using RMI

Connecting Java to Matlab using RMI

While this example only deals with communicating with a single Matlab session, matlabcontrol can handle multiple remote sessions. Whenever a new session is established, connectionEstablished(RemoteMatlabProxy proxy) is invoked on each connection listener. When a connection is lost due to Matlab closing, or in very rare cases Matlab encountering extremely severe errors, connectionLost(RemoteMatlabProxy proxy) is called. Calling methods on this proxy will lead to exceptions being thrown, as it can no longer communicate with Matlab. The proxy is passed because this information is useful when controlling multiple sessions of Matlab simultaneously.

When the “Invoke” button is pressed, the command and number of return arguments is sent to Matlab. If the number of return arguments is 0, the command will still execute but nothing will be returned. If the number is positive but less than the total number of return arguments, then only up to that number of arguments will be returned. If the number of return arguments specified exceeds the actual amount of arguments returned, a Java exception will be thrown. By default the fields are populated to return the result of “sqrt(5)“. Press “Invoke” to see what happens. Change the number of return arguments to 0, and click “Invoke” again. Now change the number to 2 and try once more.

Invoking Matlab commands from Java using JMI

Invoking Matlab commands from Java using JMI

When the Java program closes, it also exits Matlab. This is accomplished by adding a WindowListener to the program, which detects the Java closure event. It is important to call Matlab’s exit command as opposed to eval(“exit”), because all other proxy methods block (pause) until completion but in the case of exiting Matlab no signal will ever be sent by Matlab to indicate it has closed.

Parsing Matlab’s return values

Our eval commands are being sent using RemoteMatlabProxy’s returningEval(String command, int returnCount) method, whose return type is Object, because Matlab can return multiple return types. For example, the expression “sqrt(5)” will return an array of doubles, “pwd” will return a java.lang.String, and “whos” will return a complicated array of arrays with a variety of base types and Objects.

This is what occurs in Matlab R2009b, but not necessarily in past or future versions. You will have to experiment to find out what is being returned on your particular platform. The demo can help as it lists everything returned, including array contents. The demo contains the formatResult(Object result, int level) method which recursively goes through the object returned from Matlab and builds a description of what it contains. As discussed in my introductory post on matlabcontrol, Matlab functions will either return a base type, an array of base types, or a String. However, if we call a Java function inside the Matlab environment then any Java object might be returned. This isn’t actually that absurd of a situation; it might arise if you are trying to control the Matlab UI.

When returning Java objects from Matlab certain restrictions and limitations apply. First, the object must be Serializable because of the underlying use of RMI. In practice this isn’t a huge issue as a very large number of built-in Java classes are Serializable, and making your own classes Serializable is usually trivial.

The second limitation is that whatever class you send from the Matlab environment to your Java program must be defined in your Java program. For any standard built-in Java class this won’t cause issues. However, if you attempt to send over classes custom to Matlab then your Java program must have those classes in its classpath (in practice this means reference the jar file containing that class). For HG (or rather, UDD) classes, you can use the following Matlab function to create a Java class interface that can be used in your Java code to access the Matlab object, or access the jar file that contains that class as explained above:

% This will create a figure.java file in the current folder:
myClassHandle = classhandle(handle(gcf));
myClassHandle.createJavaInterface(myClassHandle.name, pwd);
 
% alternately, you can use myClassHandle.JavaInterfaces{1}
% = 'com.mathworks.hg.Figure' in this particular case
% i.e., in your java code import com.mathworks.hg.Figure

(UDD will be described in much more detail in a future article that is currently being prepared)

The third caveat is that you will be returned a copy of the Java object. This means that if you have a Java array in Matlab, send it to your Java program and then insert an object into the array, the array in Matlab will not be affected. However, you can then send that array back to Matlab, so in practice this does not cause significant issues. None of these restrictions are applicable to matlabcontrol for local sessions.

Conclusion

Today we have shown how a dedicated Matlab session can be started from a Java application, which then communicates with that Matlab session using the matlabcontrol package. This concludes my series on matlabcontrol. Please check out the matlabcontrol website for more information, examples and updates. If you use matlabcontrol, filling out this survey so that I can improve it, would be greatly appreciated.

Since the past few articles were heavy on Matlab-Java topics, the next few articles will be devoted to undocumented pure-Matlab tips and tricks, starting next week with the topic of how to customize the default menubar and toolbar actions.

JMI wrapper – local MatlabControl part 2

Wednesday, May 19th, 2010

Once again I welcome guest blogger Joshua Kaplan for his continued series on MatlabControl – the Java-to-Matlab Interface (JMI) wrapper

Last week I introduced a Java package called matlabcontrol which can be used to access Matlab from Java.

Let’s now put matlabcontrol to work from Java. Below is a very simple Java class called LocalExample which uses Swing to create a window (JFrame), a text field (JTextField), and a button (JButton). When the button is pressed, the text in the field will be evaluated in Matlab using LocalMatlabProxy.eval(…), which was explained in the previous post.

import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;
 
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
 
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.JTextField;
 
import matlabcontrol.LocalMatlabProxy;
import matlabcontrol.MatlabInvocationException;
 
/**
 * A simple demo of some of matlabcontrol's functionality.
 * 
 * @author Joshua Kaplan
 */
public class LocalExample extends JFrame
{
  /**
   * Constructs this example and displays it.
   */
  public LocalExample()
  {
    //Window title
    super("Local Session Example");
 
    //Panel to hold field and button
    JPanel panel = new JPanel();
    this.add(panel);
 
    //Input field
    final JTextField inputField = new JTextField();
    inputField.setColumns(15);
    panel.add(inputField);
 
    //Eval button
    JButton evalButton = new JButton("eval");
    panel.add(evalButton);
 
    //Eval runnable, to execute in separate (non-EDT) thread
    final ExecutorService executor = Executors.newSingleThreadExecutor();
    final Runnable evalRunnable = new Runnable()
    {
      public void run()
      {
        try
        {
          LocalMatlabProxy.eval(inputField.getText());
        }
        catch (MatlabInvocationException exc) { }
      }
    };
 
    //Eval action event for button and field
    ActionListener evalAction = new ActionListener()
    {
      public void actionPerformed(ActionEvent e)
      {
        //This uses the EDT thread, which may hang Matlab...
        //LocalMatlabProxy.eval(inputField.getText());
 
        //Execute runnable on a separate (non-EDT) thread
        executor.execute(evalRunnable);
      }
    };
    evalButton.addActionListener(evalAction);
    inputField.addActionListener(evalAction);
 
    //On closing, release resources of this frame
    this.addWindowListener(new WindowAdapter()
    {
      public void windowClosing(WindowEvent e)
      {
        LocalExample.this.dispose();
      }
    });
 
    //Display
    this.pack();
    this.setResizable(false);
    this.setVisible(true);
  }
}

We can either copy and compile the above code (remember to import the matlabcontrol JAR file in your compiler; four class files will be created), or download the already-compiled code here. Note that the already-compiled classes were compiled using JDK 1.6, so if you have Matlab R2007a (7.4) or earlier you will need to compile using an earlier Java compiler.

We now need to tell Matlab where to find both the matlabcontrol JAR file, and our LocalExample class files. We can either add the files to the static java classpath (by editing the classpath.txt file), or add them only to the current Matlab session’s dynamic classpath:

% Add Java files to current Matlab session's dynamic classpath
javaaddpath LocalExample.zip
javaaddpath matlabcontrol-3.01.jar

To run the Java program, simply type LocalExample in the Matlab Command Window – A small Java window will appear and JMI will evaluate any expression typed into it:

>> LocalExample
ans =
LocalExample[frame0,0,0,202x67,title=Local Session Example,...]

Java window calling Matlab via JMI

Java window calling Matlab via JMI

a =
          1.77245385090552

When we called LocalMatlabControl.eval(…) from the Command Window last week, what occurred behind the scenes was actually quite different from what happens when we press the “eval” button in the Java program. This is because in the Command Window everything executes in Matlab’s single main thread. When we pressed “eval”, the code executed from the Event Dispatch Thread (EDT), which is a separate thread.

EDT is used extensively by Matlab when accessing graphical components such as a figure window, uicontrols or plots. When calling a function from JMI, the calling thread always blocks (pauses) until Matlab is done completing whatever has been asked of it. So, if we called JMI/matlabcontrol from the EDT and Matlab needed to use the EDT, then everything will lock up. To fix this potential problem, when you press the “eval” button the command is sent off to a separate thread which can block without preventing Matlab from doing its work. Future versions of matlabcontrol will try to simplify this process further. matlabcontrol over a remote connection, the topic of my next post, does not suffer from this complication because Matlab and your program are not sharing the same EDT or even the same Java runtime process (JVM).

While the above Java example is quite simple, using a combination of all of the methods described throughout my previous post, a much more sophisticated program can be created. To explore the methods in more detail you can use the demo available here. The demo uses a remote connection to Matlab, but the available methods are the same. In my next and final article on this subject, I will explore controlling Matlab using matlabcontrol over a remote connection.