Posts Tagged ‘Handle graphics’

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
Bookmark and Share

Inactive Control Tooltips & Event Chaining

Wednesday, February 24th, 2010

Once again, I welcome guest blogger Matt Whitaker, who continues his series of articles.

In my last post I explored some tips on tooltips. One of these tips involved displaying tooltips on disabled uicontrols. I explained that displaying tooltips on inactive controls is problematic since Matlab appears to intercept mouse events to these inactive controls, so even setting the tooltip on the underlying Java object will not work: The java object appears not to receive the mouse-hover event and therefore does not “know” that it’s time to display the tooltip.

When Yair and I deliberated this issue, he pointed me to his comment on a previous article showing an undocumented Java technique (Java also has some…) for forcing a tooltip to appear using the ActionMap of the uicontrol’s underlying Java object to get at a postTip action. We discussed using a WindowButtonMotionFcn callback to see if the mouse was above the inactive control, then triggering the forced tooltip display. Yair then went on to remind me and I quote: “you’ll need to chain existing WindowButtonMotionFcn callbacks and take into account ModeManagers that override them.”

Frankly, having written code previously that handles callback chaining, I would rather poke myself in the eye with a fork!

The Image Processing Toolbox has the nice pair of iptaddcallback and iptremovecallback functions that largely handle these issues. But for general Matlab, there seemed to be no alternative until I remembered that events trigger callbacks. I decided to use a listener for the WindowButtonMotion event to detect the mouse motion. Event listeners were briefly explained two weeks ago and deserve a dedicated future article. The advantage of using an event listener is that we don’t disturb any existing WindowButtonMotionFcn callback. We still need to be somewhat careful that our listeners don’t do conflicting things, but it’s a lot easier than trying to manage everything through the single WindowButtonMotionFcn.

A demonstration of this appears below with some comments following (note that this code uses the FindJObj utility):

function inactiveBtnToolTip
  %Illustrates how to make a tooltip appear on an inactive control
  h = figure('WindowButtonMotionFcn',@windowMotion,'Pos',[400,400,200,200]);
  col = get(h,'color');
  lbl = uicontrol('Style','text', 'Pos',[10,160,120,20], ...
                  'Background',col, 'HorizontalAlignment','left');
  btn = uicontrol('Parent',h, 'String','Button', ...
                  'Enable','inactive', 'Pos',[10,40,60,20]);
  uicontrol('Style','check', 'Parent',h, 'String','Enable button tooltip', ...
            'Callback',@chkTooltipEnable, 'Value',1, ...
            'Pos',[10,80,180,20], 'Background',col);
  drawnow;
 
  %create the tooltip and postTip action
  jBtn = findjobj(btn);
  import java.awt.event.ActionEvent;
  javaMethodEDT('setToolTipText',jBtn,'This button is inactive');
  actionMap = javaMethodEDT('getActionMap',jBtn);
  action = javaMethodEDT('get',actionMap,'postTip');
  actionEvent = ActionEvent(jBtn, ActionEvent.ACTION_PERFORMED, 'postTip');
 
  %get the extents plus 2 pixels of the control to compare to the mouse position
  btnPos = getpixelposition(btn)+[-2,-2,4,4]; %give a little band around the control
  left = btnPos(1);
  right = sum(btnPos([1,3]));
  btm = btnPos(2);
  top =  sum(btnPos([2,4]));
 
  % add a listener on mouse movement events
  tm = javax.swing.ToolTipManager.sharedInstance; %tooltip manager
  pointListener = handle.listener(h,'WindowButtonMotionEvent',@figMouseMove);
 
  %inControl is a flag to prevent multiple triggers of the postTip action
  %while mouse remains in the button
  inControl = false;
 
  function figMouseMove(src,evtData) %#ok
    %get the current point
    cPoint = evtData.CurrentPoint;
 
    if cPoint(1) >= left && cPoint(1) <= right &&...
       cPoint(2) >= btm  && cPoint(2) <= top
 
      if ~inControl %we just entered
        inControl = true;
        action.actionPerformed(actionEvent); %show the tooltip
      end %if
    else
      if inControl %we just existed
        inControl = false;
        %toggle to make it disappear when leaving button
        javaMethodEDT('setEnabled',tm,false);
        javaMethodEDT('setEnabled',tm,true);
      end %if
    end %if
  end %gpMouseMove
 
  function windowMotion(varargin)
    %illustrate that we can still do a regular window button motion callback
    set(lbl,'String',sprintf('Mouse position: %d, %d',get(h,'CurrentPoint')));
    drawnow;
  end %windowMotion
 
  function chkTooltipEnable(src,varargin)
    if get(src,'Value')
      set(pointListener,'Enable','on');
    else
      set(pointListener,'Enable','off');
    end %if
  end %chkTooltipEnable
end %inactiveBtnToolTip

Tooltip on an inactive button

Tooltip on an inactive button

Comments on the code:

  1. The code illustrates that we can successfully add an additional listener to listen for mouse motion events while still carrying out the original WindowButtonMotionFcn callback. This makes chaining callbacks much easier.
  2. The handle.listener object has an Enable property that we can use to temporarily turn the listener on and off. This can be seen in the chkTooltipEnable() callback for the check box in the code above. If we wanted to permanently remove the listener we would simply use delete(pointListener). Note that addlistener adds a hidden property to the object being listened to, so that the listener is tied to the object’s lifecycle. If you create a listener directly using handle.listener you are responsible for it’s disposition. Unfortunately, addlistener fails for HG handles on pre-R2009 Matlab releases, so we use handle.listener directly.
  3. The code illustrates a good practice when tracking rapidly firing events like mouse movement of handling reentry into the callback while it is still processing a previous callback. Here we use a flag called inControl to prevent the postTip action being continuously fired while the mouse remains in the control.
  4. I was unable to determine if there is any corresponding action for the postTip to dismiss tips so I resorted to using the ToolTipManager to toggle its own Enable property to cleanly hide the tooltip as the mouse leaves the control.

Each Matlab callback has an associated event with it. Some of the ones that might be immediately useful at the figure-level are WindowButtonDown, WindowButtonUp, WindowKeyPress, and WindowKeyRelease. They can all be accessed through handle.listener or addlistener as in the code above.

Unfortunately, events do not always have names that directly correspond to the callback names. In order to see the list of available events for a particular Matlab object, use the following code, which relies on another undocumented function - classhandle. Here we list the events for gcf:

>> get(get(classhandle(handle(gcf)),'Events'),'Name')
ans = 
    'SerializeEvent'
    'FigureUpdateEvent'
    'ResizeEvent'
    'WindowKeyReleaseEvent'
    'WindowKeyPressEvent'
    'WindowButtonUpEvent'
    'WindowButtonDownEvent'
    'WindowButtonMotionEvent'
    'WindowPostChangeEvent'
    'WindowPreChangeEvent'

Note that I have made extensive use of the javaMethodEDT function to execute Java methods that affect swing components on Swing’s Event Dispatch Thread. I plan to write about this and related functions in my next article.

Bookmark and Share

FindJObj GUI - display container hierarchy

Tuesday, January 12th, 2010

In my previous post, I explained how the findjobj utility can be used to access a Matlab component’s underlying Java component. Findjobj has another role: displaying the component hierarchy of complex Matlab containers such as the figure window, GUIDE or the Editor.

When findjobj is called with no output arguments, the function infers that the user requests to see the GUI version, rather than to get the control’s Java handle:

>> findjobj(gcf);  % or: findjobj(gcf)

FindJObj GUI (click to zoom)

FindJObj GUI (click to zoom)

There are several note-worthy aspects in this graphical hierarchy presentation:

The hierarchy tree itself is displayed using the internal com.mathworks.hg.peer.UITreePeer Java object. This is the object that underlies the semi-documented uitree function. The hierarchy sub-components are presented as tree nodes, each having a separate icon based on the component type. In some cases (toolbar buttons for example), the component’s icon image is used for its corresponding tree node. A javax.swing.JProgressBar is presented while the tree is being populated, an action that can take a few seconds depending on the target figure’s complexity. Some tree branches which are normally uninteresting are automatically collapsed: hidden containers (these are also grayed-out), menubars, toolbars and scrollbars. In parallel to the Java container hierarchy, a separate tree branch is presented with the corresponding Matlab (Handle-Graphics, or HG) hierarchy.

Another GUI example - note the hidden (gray) items, the HG tree branch and the auto-collapsed MJToolBar container

Another GUI example - note the hidden (gray) items, the HG tree branch and the auto-collapsed MJToolBar container

Each node item gets a unique tooltip (see top screenshot above). Similarly, a unique context-menu (right-click menu) is attached to each node item with actions that are relevant for that node:

Item-specific context-menu

Item-specific context-menu

Finally, a node-selection callback is attached to the tree, that will flash a red border around the GUI control when its corresponding Java node-item is clicked/selected:

FindJObj - flashing red border around a toolbar icon

FindJObj - flashing red border around a toolbar icon

Once the tree was done, I set out to display and enable modifications of component properties and callbacks in separate adjacent panels. I used the internal com.mathworks.mlwidgets.inspector.PropertyView component to display the properties (this is the JIDE component that underlies the built-in inspect function). To prevent a JIDE run-time alert, I called com.mathworks.mwswing.MJUtilities.initJIDE. A label is added to the table’s header, displaying the currently selected sub-component’s class (e.g., “javax.swing.JButton”), and a tooltip with a color-coded list of all the control’s properties.

The callbacks table was implemented using com.jidesoft.grid.TreeTable to enable easy column resizing, but this is otherwise used as a simple data table. A checkbox was added to filter out the 30-odd standard Swing callbacks, which are non-unique to the selected sub-component (tree node). All the panels - tree, properties and callbacks - are then placed in resizable javax.swing.JSplitPanes and presented to the user.

I have omitted mention of some other undocumented features in findjobj. After all, space here is limited and the function is over 2500 lines long. I encourage you to download the utility and explore the code, and I gladly welcome your feedback.

Bookmark and Share

FindJObj - find a Matlab component’s underlying Java object

Wednesday, January 6th, 2010

In a previous post, I explained that all Matlab GUI (except the axes plotting engine) is based on Java components, and showed how we can use this information to display HTML contents in Matlab uicontrols. In other posts, I have shown how a utility called findjobj can be used to access the underlying Java components to enable customizations that are unavailable in standard Matlab: setting the line location in an edit-box, customizing button appearance, setting uicontrol callbacks, or setting list-box mouse actions. I have also shown how findjobj can be used to display the component hierarchy of complex Matlab containers such as the figure window, GUIDE or the Editor.

The time is therefore well overdue for a formal introduction of findjobj, explaining its uses and internal mechanism. Of course, readers are welcome to continue using findjobj as a black-box utility, but I think important insight can be gained from understanding its inner details. Findjobj’s code is available for free download on the MathWorks File Exchange. It is one of my favorite submissions and is apparently well-liked by users, being highly reviewed and highly downloaded.

Findjobj has two main purposes:

  1. Find the underlying Java object reference of a given Matlab handle - Historically this was the original purpose, hence the utility’s name. Findjobj was meant to extend Matlab’s standard findobj function, which does not expose Java components.
  2. Display a container’s internal components hierarchy in a graphical user interface, to facilitate visualization of complex containers. This was later extended to also display and allow modification of the sub-components’ properties and callbacks.

Today I will focus on the first (programmatic) aspect; next week I will describe the second (GUI) aspect.

Findjobj’s heart is finding a control’s underlying Java handle. Unfortunately, this is not exposed by Matlab except in very rare cases. As hard as I tried, I could not find a way to directly access the underlying Java-peer handle. I therefore resorted to getting the control’s enclosing Java frame (window) reference, and then working down its sub-components hierarchy until finding the Java object(s) which satisfy the position and/or class criteria. To get the enclosing Java frame (aka TopLevelAncestor), I use the Matlab figure’s undocumented JavaFrame property. Using this property issues a standard warning (since Matlab release R2008a) of becoming obsolete in some future Matlab release. Since it worked so far, I have turned off this warning in findjobj’s code, but note that this code may well fail in some future Matlab version. If and when JavaFrame does become obsolete, be sure to look in this blog for workarounds…

Traversing the frame’s hierarchy presents several challenges: Main-menu items are accessed using different functions than other Swing components or sub-containers, and are not automatically accessible until first displayed. I have overcome this latter challenge by simulating a menu-open action in case menus should be searched (this is off by default since it takes several seconds and also changes the GUI focus). For “regular” sub-containers, sometimes we need to loop over getComponent(…) and in some other cases over getChildAt(…).

Another challenge was presented by the fact that Java positions start at (0,0) in the top left corner increasing rightward and downward, rather than starting at (1,1) in the bottom left and increasing upward as in Matlab. Moreover, Java positions are always pixel-based and relative to their parent container, which is different from Matlab (if the Matlab units is ‘pixels’ then the value is absolute; if ‘normalized’ then it returns a non-pixel value). To further complicate matters, some Matlab controls have a different size than their Java counterparts: some controls have a 5-pixel margins while others not, some controls are shifted by a pixel or two from their container’s border (for a total offset of up to 7 pixels), while some controls (such as popup-menus) have an entirely different reported size. In theory, we could use the Matlab component’s undocumented PixelBounds property (much faster than getpixelposition), but unfortunately PixelBounds turns out to be unreliable and returns erroneous values in many cases. Finally, different Java containers/components have different ways of returning their position: for some it is a getLocation() method, for others it is getX()/getY() and for others it is the X and Y properties (that sometimes have no corresponding getX()/getY() accessor methods!).

Having finally overcome all these challenges (and quite a few smaller ones, documented within the source code), I have wrapped the algorithm in a function interface that tries to emulate findobj’s. Using findjobj can now be as easy as:

% Modify the mouse cursor when over the button
hButton = uicontrol('string','click me!');
jButton = findjobj(hButton);
jButton.setCursor(java.awt.Cursor(java.awt.Cursor.HAND_CURSOR))

Modified uicontrol cursor - a Java property

Modified uicontrol cursor - a Java property

…or as complex as:

% Find all non-button controls with the specified label
jControls = findjobj('property',{'text','click me!'}, 'not','class','button');

Space here is limited and findjobj is over 2500 lines long, so I have obviously not covered everything. I encourage you to download the utility and explore the code, and I gladly welcome your feedback.

Bookmark and Share

GUI integrated browser control

Wednesday, December 9th, 2009

Last week, I described the built-in PopupPanel object, and showed how it can be used to present popup messages with HTML content and even entire webpages. I explained that PopupPanel uses an internal browser object to achieve this. In fact, Matlab’s browser object predates PopupPanel by many years and quite a few releases. This browser object can be used as a stand-alone component that we can easily embed in our Matlab GUI applications.

Here is a simple example in which a Matlab Listbox uicontrol is used to select the contents of an adjacent browser component:

% Create a blank figure window
f=figure('Name','Browser GUI demo','Num','off','Units','norm');
 
% Add the browser object on the right
jObject = com.mathworks.mlwidgets.html.HTMLBrowserPanel;
[browser,container] = javacomponent(jObject, [], f);
set(container, 'Units','norm', 'Pos',[0.3,0.05,0.65,0.9]);
 
% Add the URLs listbox on the left
urls = {'www.cnn.com','www.bbc.co.uk','myLocalwebpage.html',...
        'www.Mathworks.com', 'UndocumentedMatlab.com'};
hListbox = uicontrol('style','listbox', 'string',urls, ...
        'units','norm', 'pos',[0.05,0.05,0.2,0.9], ...
        'userdata',browser);
 
% Set the listbox's callback to update the browser contents
cbStr=['strs = get(gcbo,''string''); ' ...
      'url = strs{get(gcbo,''value'')};' ...
      'browser = get(gcbo,''userdata''); ' ...
      'msg=[''<html><h2>Loading '' url '' - please wait''];'...
      'browser.setHtmlText(msg); pause(0.1); drawnow;'...
      'browser.setCurrentLocation(url);'];
set(hListbox,'Callback',cbStr);

Browser object integrated in Matlab GUI (click for large image)

Browser object integrated in Matlab GUI

In this simple example, we can see how the Java browser object can easily be controlled by Matlab. Specifically, we use two modes of the browser: first we present an HTML message (’Loading www.cnn.com - please wait‘) and then replacing this content with the actual webpage, if accessible. If the webpage is not accessible, an error message is displayed:

Browser message when webpage is missing (click for large image)

Browser message when webpage is missing

We can easily expand this simple example to display any HTML message or webpage, in a seamless integration within our GUI.

Now, who ever said that Matlab GUI looks static or boring???

In an unrelated note, I would like to extend good wishes to Ken Orr, who has left the Mathworks Desktop development team to join Apple a few days ago. You probably know Ken from his good work on the Desktop and the official Matlab Desktop blog. Hopefully, in his new position Ken will be able to influence Mac Java in a way that will reduce the numerous recurring issues that afflict Matlab Mac releases.

Bookmark and Share

Customizing Matlab labels

Wednesday, November 11th, 2009

As I was deliberating the topic of my weekly article, a new CSSM newsreader thread arrived today to immediately conclude the debate: The CSSM poster asked how Matlab labels can be modified to display non-ASCII characters such as the ∀ or β math symbols.

As you may recall, unlike axes text labels that support Tex/Latex, and unlike other uicontrols like buttons or listboxes that support HTML, text labels (uicontrol(’Style’,'text’,…)) do not support text formatting or special symbols.

In the above-mentioned thread, Matt Whitaker, a longstanding CSSM contributor and a Matlab-Java veteran gave a solution that shows how seemingly difficult questions sometimes have simple solutions right beneath our noses. His solution was to simply replace the uicontrol label with a Java JLabel:

%show the 'for all' and 'beta' symbols
labelStr = '<html>&#8704;&#946; <b>bold</b> <i><font color="red">label</html>';
jLabel = javaObjectEDT('javax.swing.JLabel',labelStr);
[hcomponent,hcontainer] = javacomponent(jLabel,[100,100,40,20],gcf);

Math symbols and HTML support in a Java JLabel

Math symbols and HTML support in a Java JLabel

Note that the standard Matlab text uicontrol itself is very limited in the amount of customization it supports, even when accessing its underlying Java object using the FindJObj utility. This underlying Java object is a com.mathworks.hg.peer.utils.MultilineLabel extension of Swing’s bland javax.swing.JComponent. In fact, aside from some font and color customizations (also available via the Matlab HG properties), the most useful properties that are accessible only via the Java object are few. These include Border, HorizontalAlignment, VerticalAlignment and LineWrap. This is a very short list compared to the long list of corresponding undocumented properties in the other uicontrols.

Bookmark and Share

Performance: scatter vs. line

Wednesday, October 14th, 2009

Following my previous article on the undocumented behavior of the scatter function, one of my readers, Benoit Charles, reported a discovery that in many circumstances the line function generates identical plots much faster than scatter.

Unlike scatter, line does not enable specific data-point marker customization, although the colors could be modified. On the other hand, line only uses a single handle object, saving memory and system resources compared to scatter keeping a separate handle for each data point. So, if you just need to quickly plot a bunch of scattered points then line could be a better choice than scatter.

Here is a simple code snippet, which generates identical plots and shows the performance difference:

>> x=rand(1000,1); y=rand(1000,1);
 
>> tic, for idx=1:100, cla; h=scatter(x,y); end; toc
Elapsed time is 2.521322 seconds.
 
>> props = {'LineStyle','none','Marker','o','MarkerEdge','b','MarkerSize',6};
>> tic, for idx=1:100, cla; h=line([x,x],[y,y],props{:}); end; toc
Elapsed time is 0.333369 seconds.

In the past, I have posted about other undocumented performance aspects, comparing the documented ismember function with the undocumented ismembc and about cellfun’s undocumented options. If you are aware of other similar functions having identical outputs and a significant performance difference, please let me know.

Bookmark and Share

Undocumented scatter plot behavior

Monday, October 12th, 2009

One of my blog readers, Henrik Toft, reported an undocumented behavior of the well-known scatter plot function: scatter returns a handle to an hggroup-type object that contains child handles of the data points (patch-type objects). This enables easy manipulation of specific points (for example, changing the color or marker of interesting data points).

The undocumented behavior is that when the scatter plot contains more than 100 points, the returned hggroup object only has a single child - a handle to a unified patch object that contains all the data points. This prevents customization of specific points: color can be customized via the cdata property, but this is not trivial; the marker cannot be customized at all.

Both Henrik and I initially thought this was a simple bug. But when Henrik reported this issue to MathWorks support, he got the response that this is indeed the expected behavior (i.e., not a bug but a feature), which is not documented. MathWorks did not say whether this was because they didn’t think users need more than 100 child handles, or perhaps an issue with memory/performance. Whatever the reason, I feel that this behavior/feature should at least be documented:

>> hggroup = scatter(rand(99,1),rand(99,1));
>> size(get(hggroup,'Children'))
ans =
    99     1
 
>> hggroup = scatter(rand(100,1),rand(100,1));
>> size(get(hggroup,'Children'))
ans =
   100     1
 
>> hggroup = scatter(rand(101,1),rand(101,1));
>> size(get(hggroup,'Children'))
ans =
     1     1

Workaround: use the ‘v6′ option. Unfortunately, this option is deprecated and marked as obsolete by Matlab, with the warning that it will be removed in a future Matlab version. I hope this will not be done until a better workaround for the above-reported issue is implemented in the scatter function:

>> hPatches = scatter('v6',rand(101,1),rand(101,1));
Warning: The 'v6' argument to SCATTER is deprecated, and will no longer be supported in a future release.
> In usev6plotapi>warnv6args at 84
  In usev6plotapi at 40
  In scatter at 39
 
>> size(hPatches)
ans =
   101     1

If you have detected any other undocumented behavior, function or feature in Matlab, please report them in the comments section below, or directly by email to me: altmany at gmail dot com.

Bookmark and Share