uitools – Undocumented Matlab https://undocumentedmatlab.com/blog_old Charting Matlab's unsupported hidden underbelly Tue, 29 Oct 2019 15:26:09 +0000 en-US hourly 1 https://wordpress.org/?v=4.4.1 Customizing the standard figure toolbar, menubarhttps://undocumentedmatlab.com/blog_old/customizing-standard-figure-toolbar-menubar https://undocumentedmatlab.com/blog_old/customizing-standard-figure-toolbar-menubar#comments Wed, 09 Jan 2013 18:00:12 +0000 https://undocumentedmatlab.com/?p=3461 Related posts:
  1. uisplittool & uitogglesplittool callbacks Matlab's undocumented uisplittool and uitogglesplittool are powerful toolbar controls - this article explains how to customize their behavior...
  2. Figure toolbar components Matlab's toolbars can be customized using a combination of undocumented Matlab and Java hacks. This article describes how to access existing toolbar icons and how to add non-button toolbar components....
  3. uisplittool & uitogglesplittool Matlab's undocumented uisplittool and uitogglesplittool are powerful controls that can easily be added to Matlab toolbars - this article explains how...
  4. Customizing figure toolbar background Setting the figure toolbar's background color can easily be done using just a tiny bit of Java magic powder. This article explains how. ...
]]>
A few days ago, a client asked me to integrate an MRU (most-recently-used) file list in a Matlab GUI window. The naive approach was to add a new “Recent files” main menu, but this would look bad. Today I explain how to integrate the MRU list into the toolbar’s standard “Open File” button, as well as into the standard “File” main menu.

Note: this relies on earlier articles about customizing the figure menubar, so if you are not comfortable with this topic you might benefit from reading these earlier articles.

Customizing the standard “File” main menu is easy. First, let’s find the “File” main menu’s handle, and add an MRU sub-menu directly to it:

hFileMenu = findall(gcf, 'tag', 'figMenuFile');
hMruMenu = uimenu('Label','Recent files', 'Parent',hFileMenu);

Our new MRU menu item is created at the end (in this case, at the bottom of the “File” main menu list). Let’s move it upward, between “New” and “Open…”, by reordering hFileMenu‘s Children menu items:

hAllMenuItems = allchild(hFileMenu);
set(hFileMenu, 'Children',fliplr(hAllMenuItems([2:end-1,1,end])));  % place in 2nd position, just above the "Open" item

Now let’s fix the “Open…” menu item’s callback to point to our custom openFile() function (unfortunately, the “Open…” menu item has no tag, so we must rely on its label to get its handle):

hOpenMenu = findall(hFileMenu, 'Label', '&Open...');
set(hOpenMenu, 'Callback',@openFile);

Finally, let’s add the MRU list as a sub-menu of the new hMruMenu. I assume that we have a getMRU() function in our code, which returns a cell-array of filenames:

% Add the list of recent files, one item at a time
filenames = getMRU();
for fileIdx = 1 : length(filenames)
    uimenu(hMruMenu, 'Label',filenames{fileIdx}, 'Callback',{@openFile,filenames{fileIdx}});
end

Modified standard figure menu-bar

Modified standard figure menu-bar


Clicking the main “Open…” menu item calls our openFile() function without the optional filename input argument, while selecting one of the MRU files will call the openFile() function with that specific filename as input. The openFile() function could be implemented something like this:

% Callback for the open-file functionality (toolbar and menubar)
function openFile(hObject,eventData,filename)
    % If no filename specified, ask for it from the user
    if nargin < 3
        filename = uigetfile({'*.csv','Data files (*.csv)'}, 'Open data file');
        if isempty(filename) || isequal(filename,0)
            return;
        end
    end
 
    % Open the selected file and read the data
    data = readDataFile(filename);
 
    % Update the display
    updateGUI(data)
end

We can take this idea even further by employing HTML formatting, as I have shown in my first article of the menubar mini-series:

HTML-rendered menu items

HTML-rendered menu items

Customizing the standard toolbar’s “Open File” button

Note: this relies on earlier articles about customizing the figure toolbar, so if you are not comfortable with this topic you might benefit from reading these earlier articles.

The basic idea here is to replace the standard toolbar’s “Open File” pushbutton with a new uisplittool button that will contain the MRU list in its picker-menu.

The first step is to get the handle of the toolbar’s “Open File” button:

hOpen = findall(gcf, 'tooltipstring', 'Open File');
hOpen = findall(gcf, 'tag', 'Standard.FileOpen');  % Alternative

The second alternative is better for non-English Matlab installations where the tooltip text may be different, or in cases where we might have another GUI control with this specific tooltip. On the other hand, the 'Standard.FileOpen' tag may be different in different Matlab releases. So choose whichever option is best for your specific needs.

Assuming we have a valid (non-empty) hOpen handle, we get its properties data for later use:

open_data = get(hOpen);
hToolbar = open_data.Parent;

We have all the information we need, so we can now simply delete the existing toolbar open button, and create a new split-button with the properties data that we just got:

delete(hOpen);
hNewOpen = uisplittool('Parent',hToolbar, ...
                       'CData',open_data.CData, ...
                       'Tooltip',open_data.TooltipString, ...
                       'ClickedCallback',@openFile);

As with the menubar, the button is now created, but it appears on the toolbar’s right edge. Let’s move it to the far left. We could theoretically reorder hToolbar‘s Children as for the menubar above, but Matlab has an internal bug that causes some toolbar buttons to misbehave upon rearranging. Using Java solves this:

drawnow;  % this innocent drawnow is *very* important, otherwise Matlab might crash!
jToolbar = get(get(hToolbar,'JavaContainer'),'ComponentPeer');
jButtons = jToolbar.getComponents;
jToolbar.setComponentZOrder(jButtons(end),2);  % Move to the position between "New" and "Save"
jToolbar.revalidate;  % update the toolbar's appearance (drawnow will not do this)

Finally, let’s add the list of recent files to the new split-button’s picker menu:

% (Use the same list of filenames as for the menubar's MRU list)
jNewOpen = get(hNewOpen,'JavaContainer');
jNewOpenMenu = jNewOpen.getMenuComponent;
for fileIdx = 1 : length(filenames)
    jMenuItem = handle(jNewOpenMenu.add(filenames{fileIdx}),'CallbackProperties');
    set(jMenuItem,'ActionPerformedCallback',{@openFile,filenames{fileIdx}});
end

Modified standard figure toolbar

Modified standard figure toolbar

Clicking the main Open button calls our openFile() function without the optional filename input argument, while clicking the picker button (to the right of the main Open button) and selecting one of the files will call the openFile() function with that specific filename as input.

That’s it. Quite painless in fact.

]]>
https://undocumentedmatlab.com/blog_old/customizing-standard-figure-toolbar-menubar/feed 12
Uitable customization reporthttps://undocumentedmatlab.com/blog_old/uitable-customization-report https://undocumentedmatlab.com/blog_old/uitable-customization-report#comments Wed, 03 Aug 2011 18:00:25 +0000 https://undocumentedmatlab.com/?p=2396 Related posts:
  1. Uitable sorting Matlab's uitables can be sortable using simple undocumented features...
  2. Date selection components The JIDE package, pre-bundled in Matlab, contains several GUI controls for selecting dates - this article explains how they can be used...
  3. Tri-state checkbox Matlab checkboxes can easily be made to support tri-state functionality....
  4. Font selection components Several built-in components enable programmatic font selection in Matlab GUI - this article explains how. ...
]]>
In last week’s report about uitable sorting, I offered a report that I have written which covers uitable customization in detail. Several people have asked for more details about the contents of this report. This is a reasonable request, and so in today’s post I will discuss in a bit more detail the highlights of what can be achieved to customize Matlab uitables. For the fine details, well, get my uitable report (45 pages PDF, $25).

1. Introduction

Here I discuss the evolution of the uitable control over the past decade, from its initially semi-documented status to today. I explain the similarities and differences between the control’s versions and explain how they can both be accessed today.

I also provide references to online resources for both Matlab’s uitable‘s underlying Java components, as well as multiple alternatives using different technologies, that have been used and reported over the years.

2. Customizing uitable

In this section I explore the sub-component hierarchy of the uitable controls. I show how the scrollbar sub-components can be accessed (this will be used in section 4 below), as well as the table header and data grid. This is the entry point for uitable customization.

annotated uitable sub-components

annotated uitable sub-components

I explain how individual cells can be modified without requiring the entire data set to be updated. This is very important in large data sets, to prevent flicker and improve performance.

I show how HTML can be used to format data cell contents (even images) and tooltips:

uitable with HTML cell contents and tooltip

uitable with HTML cell contents and tooltip


uitable with cell images

uitable with cell images

3. Cell renderers and cell editors

This section explains the role of the cell-renderer in the visual appearance of the cell, and of cell-editors in the way that cells interact with the user for data modification. I explain such customizations from the simple (setting a column’s background color) to the complex (cell-specific tooltips and colors; color-selection cell-editor):


uitable with a non-standard cell-renderer

uitable with a non-standard cell-renderer


uitable with a non-standard cell-rendereruitable with a non-standard cell-editor

uitable with a non-standard cell-renderer (left) and cell-editor (right)


uitable with custom CellRenderer and CellEditor

uitable with custom CellRenderer and CellEditor

Cell renderers can also be used to set custom text format of cell contents and cell-specific tooltips (note the top table in the following screenshot):

uitable with custom CellRenderers (note text formats and cell-specific tooltips)

uitable with custom CellRenderers (note text formats and cell-specific tooltips)


(also note the colored table headers in the bottom table)

4. Table callbacks

This section of my uitable report presents the different callback properties that are settable in the old and new uitable, for events such as cell selection, data modification, key press, and mouse click. The discussion includes a working code example for validating user input and reverting invalid edits. The section also includes a discussion of how to avoid and overcome problems that may occur with the callback execution.

5. Customizing scrollbars, column widths and selection behavior

This section explains how to control the scrollbars behavior. For example, hiding the horizontal (bottom) scrollbar, automatically displaying it when the data width is larger than the table width. I also show how to control the column widths.

I then show how to customize the data selection policy: Can multiple cells be selected? perhaps only one cell at a time? or maybe a single large interval of cells? – this is all customizable. I then explain how the selection can be done and accessed programmatically. Ever wanted to set the cursor on cell A1 after some system event has occurred? – this will show you how to do it. Ever wanted to use non-standard selection colors (background/foreground)? – this can also be done.

6. Data sorting

Table sorting was discussed in last week’s article. This section expands on that article, and explains how the sorting can be customized, controlled, and accessed programmatically, and how sorted rows can be retrieved by the user.

Multi-column sorting with blue sort-order numbers

Multi-column sorting with blue sort-order numbers

7. Data filtering

Data filtering is the ability to filter only a specified sub-set of rows for display (just like in Excel). This section explains how to do it (it’s so easy!).

uitable data filtering

uitable data filtering

8. JIDE customizations

The new uitable is based on an underlying JIDE table. This sectino explains how we can use this to our advantage for some simple and useful. Customization.

For example: have you wondered some time why is it that columns can only be resized by dragging the tiny divider in the table header? Why can’t the columns and rows be resized by dragging the grid lines? Well, it turns out that they can, with just a tiny bit of JIDE magic powder, explained here:

Resizing columns

Resizing columns

Similarly, this section explains how we can use JIDE to merge together adjacent cells:

Example of two table cell-spans (1x2 and 2x2)

Example of two table cell-spans (1x2 and 2x2)

I also show how to attach a custom context-menu (right-click menu) to the table header row:

Custom header-row context-menu

Custom header-row context-menu

9. Controlling the table structure (adding/removing rows)

This section discusses the matter of dynamically adding and removing table rows. While this is easy to do in the old uitable, this is unfortunately not the case in the new uitable.

10. Run-time performance

This section discusses ways to improve the run-time performance (speed) of uitable, both new and old. For additional information regarding run-time performance, refer to my book “MATLAB Performance Tuning“.

11. Final remarks

Here I present a workaround for a long-time table bug. Also, I present my createTable utility that wraps table creation in Matlab:

createTable utility screenshot (note the action buttons, sortable columns, and customized CellEditor)

createTable utility screenshot (note the action buttons, sortable columns, and customized CellEditor)

Appendix – JIDE Grids

Finally, this appendix presents an overview of the wide array of components provided by JIDE and available in Matlab. uitable uses only one of these components (the SortableTable). In fact, there are many more such controls that we can use in our GUIs.

These include a wide selection of combo-box (drop-down) controls – calculator, file/folder selection, date selection, color selection, multi-elements selection etc.

Date selection comb-box

Date selection combo-box

In addition, a very wide selection of lists, trees and table types is available.

TreeTable example

TreeTable example

Also included is a set of specialized editbox controls for accepting IP addresses and credit card numbers:

IP address entry boxcredit-card entry boxcredit-card entry box

IP address and credit-card entry boxes

While not explaining all these controls in detail (this could take hundreds of pages), this section does say a few words on each of them, and includes links to online resources for further exploration.

]]>
https://undocumentedmatlab.com/blog_old/uitable-customization-report/feed 74
Uitable sortinghttps://undocumentedmatlab.com/blog_old/uitable-sorting https://undocumentedmatlab.com/blog_old/uitable-sorting#comments Tue, 26 Jul 2011 18:00:01 +0000 https://undocumentedmatlab.com/?p=2391 Related posts:
  1. Uitable customization report Matlab's uitable can be customized in many different ways. A detailed report explains how. ...
  2. Tab panels – uitab and relatives This article describes several undocumented Matlab functions that support tab-panels...
  3. treeTable A description of a sortable, groupable tree-table control that can be used in Matlab is provided. ...
  4. Types of undocumented Matlab aspects This article lists the different types of undocumented/unsupported/hidden aspects in Matlab...
]]>
uitable is probably the most complex basic GUI controls available in Matlab. It displays data in a table within a figure, with settable properties as with any other Matlab Handle-Graphics (HG) control. After many years in which the uitable was available but semi-documented and not officially supported in Matlab, it finally became fully documented and supported in R2008a (aka Matlab 7.6). At that time its internal implementation has changed from a MathWorks-developed Java table to a JIDE-based Java table (another JIDE-derived table was described here last year). Since R2008a, both versions of uitable are available – the old version is available by adding the ‘v0’ input arg.

Matlab’s uitable exposes only a very limited subset of functionalities and properties to the user. Numerous other functionalities are available by accessing the underlying Java table and hidden Matlab properties. Today I will describe a very common need in GUI tables, that for some unknown reason is missing in Matlab’s uitable: Sorting table data columns.

Last week I explained how we can modify table headers of an ActiveX table control to display sorting icons. In that case, sorting was built-in the control, and the question was just how to display the sorting arrow icon. Unfortunately, Matlab’s uitable does not have sorting built-in, although it’s quite easy to add it, as I shall now show.

Old uitable sorting

The old uitable is the default control used until R2007b, or that can be selected with the ‘v0’ input arg since R2008a. It was based on an internal MathWorks extension of the standard Java Swing JTable – a class called com.mathworks.widgets.spreadsheet.SpreadsheetTable.

Users will normally try to sort columns by clicking the header. This has been a deficiency of JTable for ages. To solve this for the old (pre-R2008a) uitable, download one of several available JTable sorter classes, or my TableSorter class (available here). Add the TableSorter.jar file to your static java classpath (via edit('classpath.txt')) or your dynamic classpath (javaaddpath('TableSorter.jar')).

% Display the uitable and get its underlying Java object handle
[mtable,hcontainer] = uitable('v0', gcf, magic(3), {'A', 'B', 'C'});   % discard the 'v0' in R2007b and earlier
jtable = mtable.getTable;   % or: get(mtable,'table');
 
% We want to use sorter, not data model...
% Unfortunately, UitablePeer expects DefaultTableModel not TableSorter so we need a modified UitablePeer class
% But UitablePeer is a Matlab class, so use a modified TableSorter & attach it to the Model
if ~isempty(which('TableSorter'))
   % Add TableSorter as TableModel listener
   sorter = TableSorter(jtable.getModel());
   jtable.setModel(sorter);
   sorter.setTableHeader(jtable.getTableHeader());
 
   % Set the header tooltip (with sorting instructions)
   jtable.getTableHeader.setToolTipText('<html>&nbsp;<b>Click</b> to sort up; <b>Shift-click</b> to sort down<br />&nbsp;...</html>');
 
else
   % Set the header tooltip (no sorting instructions...)
   jtable.getTableHeader.setToolTipText('<html>&nbsp;<b>Click</b> to select entire column<br />&nbsp;<b>Ctrl-click</b> (or <b>Shift-click</b>) to select multiple columns&nbsp;</html>');
end

Sorted uitable - old version

Sorted uitable - old version

New uitable sorting

The new uitable is based on JIDE’s com.jidesoft.grid.SortableTable and so has built-in sorting support – all you need to do is to turn it on. First get the underlying Java object using my FindJObj utility:

% Display the uitable and get its underlying Java object handle
mtable = uitable(gcf, 'Data',magic(3), 'ColumnName',{'A', 'B', 'C'});
jscrollpane = findjobj(mtable);
jtable = jscrollpane.getViewport.getView;
 
% Now turn the JIDE sorting on
jtable.setSortable(true);		% or: set(jtable,'Sortable','on');
jtable.setAutoResort(true);
jtable.setMultiColumnSortable(true);
jtable.setPreserveSelectionsAfterSorting(true);

Note: the Matlab mtable handle has a hidden Sortable property, but it has no effect – use the Java property mentioned above instead. I assume that the hidden Sortable property was meant to implement the sorting behavior in R2008a, but MathWorks never got around to actually implement it, and so it remains this way to this day.

A more detailed report

I have prepared a 45-page PDF report about using and customizing Matlab’s uitable, which greatly expands on the above. This report is available for $25 here (please allow up to 48 hours for email delivery). The report includes the following (more details here):

  • comparison of the old vs. the new uitable implementations
  • description of the uitable properties and callbacks
  • alternatives to uitable using a variety of technologies
  • updating a specific cell’s value
  • setting background and foreground colors for a cell or column
  • using dedicated cell renderer and editor components
  • HTML processing
  • setting dynamic cell-specific tooltip
  • setting dynamic cell-specific drop-down selection options
  • using a color-selection drop-down for cells
  • customizing scrollbars
  • customizing column widths and resizing
  • customizing selection behavior
  • data sorting (expansion of today’s article)
  • data filtering (similar to Excel’s data filtering control)
  • merging table cells
  • programmatically adding/removing rows
  • numerous links to online resources
  • overview of the JIDE grids package, which contains numerous extremely useful GUI controls and components
]]>
https://undocumentedmatlab.com/blog_old/uitable-sorting/feed 46
An interesting uitree utilityhttps://undocumentedmatlab.com/blog_old/interesting-uitree-utility https://undocumentedmatlab.com/blog_old/interesting-uitree-utility#comments Wed, 30 Mar 2011 18:00:59 +0000 https://undocumentedmatlab.com/?p=2218 Related posts:
  1. Figure toolbar components Matlab's toolbars can be customized using a combination of undocumented Matlab and Java hacks. This article describes how to access existing toolbar icons and how to add non-button toolbar components....
  2. Customizing uitree This article describes how to customize Matlab GUI tree controls created using the undocumented uitree function...
  3. Customizing uitree nodes – part 2 This article shows how Matlab GUI tree nodes can be customized with checkboxes and similar controls...
  4. Uitab colors, icons and images Matlab's semi-documented tab panels can be customized using some undocumented hacks...
]]>
“uitree” is consistently one of the most-popular search terms on this site, together with “uitable” and “uitab”. I also receive frequent questions about tree components in Matlab.

I already wrote a series of articles on Matlab’s built-in semi-documented uitree (starting here), and I am on a constant lookout for additional interesting angles on uitree to post here. Brett Shoelson’s recent review of 2005’s Pick-of-the-Week utilities, provided me with such an opportunity.

One of 2005’s featured utilities, Structure Explorer by Hassan Lahdili, originally written using Microsoft’s TreeView ActiveX control, was apparently rewritten using Matlab’s Java-based uitree. This enables the utility to run on non-Windows platforms and have a more consistent look-and-feel with Matlab’s Java-based GUI:

Hassan Lahdili's Structure Explorer (click to enlarge)

Hassan Lahdili's Structure Explorer (click to enlarge)

Hassan’s ExploreStruct utility, in addition to being useful as-is, provides a very useful learning tool for uitree integration in Matlab GUI. This utility uses custom icons for different node types, custom callbacks for node expansion (NodeWillExpandCallback) and node selection (NodeSelectedCallback), and tree context (right-click) menu.

Unfortunately, it appears that the ExploreStruct utility has not been updated for compatibility with the latest Matlab releases. This causes numerous warning messages about not using ‘v0’ when calling uitree and uitreenode. I also had to add a call to drawnow following the uitree‘s creation in line #30, otherwise the tree did not appear (due to EDT issues). Also, I had to comment out line #83 (set(root,’UIContextMenu’, cmenu);) which caused an error (“There is no ‘UIContextMenu’ property in the ‘com.mathworks.hg.peer.UITreeNode’ class”) – the tree’s context-menu actually works even without this line.

Finally, I had to fix line #182 so that the node icons will appear correctly:

%pth = [matlabroot, '\work\exp_struct_icons\'];  %old
pth = [fileparts(which(mfilename)) '\exp_struct_icons\'];  %new

ExploreStruct is not documented and does not have extensive error-checking that I would like to see in real-world applications. But it is relatively easy to read and understand due to its use of internal functions and meaningful variable names.

Altogether, aside from the minor nuances mentioned above, I believe that readers who are interested in implementing custom tree objects in their Matlab GUI can learn a lot from this utility, and you can easily adapt its code for your own needs (or if you can’t, I am always willing to help).

]]>
https://undocumentedmatlab.com/blog_old/interesting-uitree-utility/feed 5
Hierarchical Systems with UDDhttps://undocumentedmatlab.com/blog_old/hierarchical-systems-with-udd https://undocumentedmatlab.com/blog_old/hierarchical-systems-with-udd#comments Wed, 02 Mar 2011 18:00:25 +0000 https://undocumentedmatlab.com/?p=2146 Related posts:
  1. Introduction to UDD UDD classes underlie many of Matlab's handle-graphics objects and functionality. This article introduces these classes....
  2. Creating a simple UDD class This article explains how to create and test custom UDD packages, classes and objects...
  3. UDD Properties UDD provides a very convenient way to add customizable properties to existing Matlab object handles...
  4. UDD Events and Listeners UDD event listeners can be used to listen to property value changes and other important events of Matlab objects...
]]>
Once again I welcome guest blogger Donn Shull, who continues his multi-part series about Matlab’s undocumented UDD objects.

We have looked at the tools for working with UDD classes, and created a simple UDD class. Today I shall show how to create a hierarchy of UDD objects.

Creating hierarchical structures with UDD objects

UDD is the foundation for both Handle Graphics (HG) and Simulink. Both are hierarchical systems. It stands to reason that UDD would offer support for hierarchical structures. It is straightforward to connect UDD objects together into searchable tree structures. All that is necessary is a collection of UDD objects that don’t have any methods or properties named 'connect', 'disconnect', 'up', 'down', 'left', 'right' or 'find'.

We illustrate the technique by creating a hierarchy of simple.objects as shown in the following diagram:

Sample UDD objects hierarchy

Sample UDD objects hierarchy

To begin we create five instances of the simple.object class from the previous article:

% Remember that simple.object accepts a name and a value
a = simple.object('a', 1);
b = simple.object('b', 1);
c = simple.object('c', 0);
d = simple.object('d', 1);
e = simple.object('e', 1);

To form the structure we use the connect method. We can use either dot notation or the Matlab syntax:

% Dot-notation examples:
a.connect(b, 'down');
b.connect(a, 'up');       % alternative to the above
 
% Matlab notation examples:
connect(a, b, 'down');
connect(b, a, 'up');      % alternative to the above

Next, connect node c into our hierarchy. There are several options here: We can use ‘down’ to connect a to c. Or we could use ‘up’ to connect c to a. Similarly, we can use either ‘left’ or ‘right’ to connect b and c. Here’s one of the many possible ways to create our entire hierarchy:

b.connect(a, 'up');
c.connect(b, 'left');
d.connect(b, 'up');
e.connect(d, 'left');

Inspecting UDD hierarchy structures

We now have our structure and each object knows its connection to other objects. For example, we can inspect b’s connections as follows:

>> b.up
ans =
  Name: a
 Value: 1.000000
 
>> b.right
ans =
  Name: c
 Value: 0.000000
 
>> b.down
ans =
  Name: d
 Value: 1.000000

We can search our structure by using an undocumented form of the built-in find command. When used with connected UDD structures, find can be used in the following form:

objectArray = find(startingNode, 'property', 'value', ...)

To search from the top of our hierarchy for objects of type simple.object we would use:

>> find(a, '-isa', 'simple.object')
ans =
        simple.object: 5-by-1    % a, b, c, d, e

Which returns all the objects in our structure, since all of them are simple.objects. If we repeat that command starting at b we would get:

>> find(b, '-isa', 'simple.object')
ans =
	simple.object: 3-by-1    % b, d, e

find searches the structure downward from the current node. Like many Matlab functions, find can be used with multiple property value pairs, so if we want to find simple.object objects in our structure with Value property =0, we would use the command:

>> find(a, '-isa', 'simple.object', 'Value', 0)
ans =
  Name: c
 Value: 0.000000

Visualizing a UDD hierarchy

Hierarchical structures are also known as tree structures. Matlab has an undocumented function for visualizing and working with trees namely uitree. Yair has described uitree in a series of articles. Rather than following the techniques in shown in Yair’s articles, we are going to use a different method that will allow us to introduce the following important techniques for working with UDD objects:

  • Subclassing, building your class on the foundation of a parent class
  • Overloading properties and methods of the superclass
  • Using meta-properties GetfFunction and SetFunction

Because the steps shown below will subclass an HG class, they will modify our simple.object class and probably make it unsuitable for general use. Yair has shown that uitree is ready made for displaying HG trees and we saw above that HG is a UDD system. We will use the technique from uitools.uibuttongroup to make our simple.object class a subclass of the HG class hg.uipanel. Modify the class definition file as follows:

% class definition
superPackage = findpackage('hg');
superClass = findclass(superPackage, 'uipanel');
simpleClass = schema.class(simplePackage, 'object',superClass);

Now we can either issue the clear classes command or restart Matlab and then recreate our structure. The first thing that you will notice is that when we create the first simple.object that a figure is also created. This is expected and is the reason that this technique is not useful in general. We will however use this figure to display our structure with the following commands:

t = uitree('v0', 'root', a);  drawnow;
t.expand(t.getRoot);  drawnow;
t.expand(t.getRoot.getFirstChild);

Simple structure presented in a Matlab uitree

Simple structure presented in a Matlab uitree

The label on each of our objects is ‘uipanel’ and this is probably not what we want. If we inspect our object or its hg.uipanel super-class (note: this would be a great time to use Yair’s uiinspect utility), we can see there is a Type property that has a value of ‘uipanel’. Unfortunately this property is read-only, so we cannot change it. We can however overload it by placing a schema.prop in our class definition named Type. This will allow us to overload or replace the parent’s Type property with our own definition:

p = schema.prop(simpleClass, 'Type', 'string');
p.FactoryValue = 'simple.object';

Once again, issue the clear classes command or restart Matlab, then recreate our structure. Our tree now has each node labeled with the ‘simple.object’ label:

Corrected node names for our UDD structure

Corrected node names for our UDD structure

This is a little more descriptive but what would really be nice is if we could label each node with the value of the Name property. As luck would have it, we can do just that. When we add a property to a UDD class we are adding an object of type schema.prop. So our properties have their own properties and methods (so-called meta-data). We are going to set the GetFunction property of our Type property. GetFunction holds a handle of the function to be called whenever the property is accessed:

p = schema.prop(simpleClass, 'Type', 'string');
p.GetFunction = @getType;

The prototype for the function that GetFunction references has three inputs and one output: The inputs are the handle of the object possessing the property, the value of that property, and the property object. The output is the value that will be supplied when the property is accessed. So our GetFunction can be written to supply the value of the Name property whenever the Type property value is being read:

function propVal = getType(self, value, prop)
   propVal = self.Name;
end

Alternately, as a single one-liner in the schema definition file:

p.GetFunction = @(self,value,prop) self.Name;

Similarly, there is a corresponding SetFunction that enables us to intercept changes to a property’s value and possibly disallow invalid values.

With these changes when we recreate our uitree we obtain:

Overloaded property GetFunction

Overloaded property GetFunction

A Java class for UDD trees

We will have more to say about the relationship between UDD and Java in a future article. For now we simply note that the com.mathworks.jmi.bean.UDDObjectTreeModel class in the JMI package provides some UDD tree navigation helper functions. Methods include getChild, getChildCount, getIndexOfChild and getPathToRoot. The UDDObjectTreeModel constructor requires one argument, an instance of your UDD tree root node:

% Create a UDD tree-model instance
>> uddTreeModel = com.mathworks.jmi.bean.UDDObjectTreeModel(a);
 
% Get index of child e and its parent b:
>> childIndex = uddTreeModel.getIndexOfChild(b, e)
childIndex =
     1
 
% Get the root's first child (#0):
>> child0 = uddTreeModel.getChild(a, 0)
child0 =
  Name: b
 Value: 1.000000
 
% Get the path from node e to the root:
>> path2root = uddTreeModel.getPathToRoot(e)
path2root =
com.mathworks.jmi.bean.UDDObject[]:
    [simple_objectBeanAdapter2]      % <= a
    [simple_objectBeanAdapter2]      % <= b
    [simple_objectBeanAdapter2]      % <= e
 
>> path2root(3)
ans =
  Name: e
 Value: 1.000000

We touched on a few of the things that you can do by modifying the properties of a schema.prop in this article. In the following article we will take a more detailed look at this essential class.

]]>
https://undocumentedmatlab.com/blog_old/hierarchical-systems-with-udd/feed 5
uisplittool & uitogglesplittool callbackshttps://undocumentedmatlab.com/blog_old/uisplittool-uitogglesplittool-callbacks https://undocumentedmatlab.com/blog_old/uisplittool-uitogglesplittool-callbacks#comments Wed, 15 Dec 2010 18:00:35 +0000 https://undocumentedmatlab.com/?p=1999 Related posts:
  1. uiundo – Matlab’s undocumented undo/redo manager The built-in uiundo function provides easy yet undocumented access to Matlab's powerful undo/redo functionality. This article explains its usage....
  2. Figure toolbar components Matlab's toolbars can be customized using a combination of undocumented Matlab and Java hacks. This article describes how to access existing toolbar icons and how to add non-button toolbar components....
  3. Inactive Control Tooltips & Event Chaining Inactive Matlab uicontrols cannot normally display their tooltips. This article shows how to do this with a combination of undocumented Matlab and Java hacks....
  4. uisplittool & uitogglesplittool Matlab's undocumented uisplittool and uitogglesplittool are powerful controls that can easily be added to Matlab toolbars - this article explains how...
]]>
Last week, I presented the undocumented uisplittool and uitogglesplittool functions and showed how they can be added to a Matlab figure toolbar. Today I wish to conclude this topic by explaining how these controls can be customized with user-defined callbacks and pop-up menus.

Callback functionality

Both uisplittool and uitogglesplittool have a Callback property, in addition to the standard ClickedCallback property that is available in uipushtools and uitoggletools.

The standard ClickedCallback is invoked when the main button is clicked, while Callback is invoked when the narrow arrow button is clicked. uitogglesplittool, like uitoggletool, also has settable OnCallback and OffCallback callback properties.

The accepted convention is that ClickedCallback should invoke the default control action (in our case, an Undo/Redo of the topmost uiundo action stack), while Callback should display a drop-down of selectable actions.

While this can be done programmatically using the Callback property, this functionality is already pre-built into uisplittool and uitogglesplittool for our benefit. To access it, we need to get the control’s underlying Java component.

Accessing the underlying Java component is normally done using the findjobj utility, but in this case we have a shortcut: the control handle’s hidden JavaContainer property that holds the underlying com.mathworks.hg.peer.SplitButtonPeer (or .ToggleSplitButtonPeer) Java reference handle. This Java object’s MenuComponent property returns a reference to the control’s drop-down sub-component (which is a com.mathworks.mwswing.MJPopupMenu object):

>> jUndo = get(hUndo,'JavaContainer')
jUndo =
com.mathworks.hg.peer.SplitButtonPeer@f09ad5
 
>> jMenu = get(jUndo,'MenuComponent')  % or: =jUndo.getMenuComponent
jMenu =
com.mathworks.mwswing.MJPopupMenu[Dropdown Picker ButtonMenu,...]

Let’s add a few simple textual options:

jOption1 = jMenu.add('Option #1');
jOption1 = jMenu.add('Option #2');
set(jOption1, 'ActionPerformedCallback', 'disp(''option #1'')');
set(jOption2, 'ActionPerformedCallback', {@myCallbackFcn, extraData});

setting uisplittool & uitogglesplittool popup-menus

setting uisplittool & uitogglesplittool popup-menus

Popup-menus are described in more detail elsewhere (and in future articles). In the past I have already explained how icons and HTML markup can be added to menu items. Sub-menus can also be added.

A complete example

Let’s now use this information, together with last year’s set of articles about Matlab’s undocumented uiundo functionality, to generate a complete and more realistic example, of undo/redo toolbar buttons.

Undo and redo are actions that are particularly suited for uisplittool, since its main button enables us to easily undo/redo the latest action (like a simple toolbar button, by clicking the main uisplittool button) as well as select items from the actions drop-down (like a combo-box, by clicking the attached arrow button) – all this using a single component.

% Display our GUI
hEditbox = uicontrol('style','edit', 'position',[20,60,40,40]); 
set(hEditbox, 'Enable','off', 'string','0');
hSlider = uicontrol('style','slider','userdata',hEditbox);
set(hSlider,'Callback',@test_uiundo);  
 
% Display the figure toolbar that was hidden by the uicontrol function
set(gcf,'Toolbar','figure');
 
% Add the Undo/Redo buttons
hToolbar = findall(gcf,'tag','FigureToolBar');
hUndo = uisplittool('parent',hToolbar);
hRedo = uitogglesplittool('parent',hToolbar);
 
% Load the Redo icon
icon = fullfile(matlabroot,'/toolbox/matlab/icons/greenarrowicon.gif');
[cdata,map] = imread(icon);
 
% Convert white pixels into a transparent background
map(find(map(:,1)+map(:,2)+map(:,3)==3)) = NaN;
 
% Convert into 3D RGB-space
cdataRedo = ind2rgb(cdata,map);
cdataUndo = cdataRedo(:,[16:-1:1],:);
 
% Add the icon (and its mirror image = undo) to latest toolbar
set(hUndo, 'cdata',cdataUndo, 'tooltip','undo','Separator','on', ...
           'ClickedCallback','uiundo(gcbf,''execUndo'')');
set(hRedo, 'cdata',cdataRedo, 'tooltip','redo', ...
           'ClickedCallback','uiundo(gcbf,''execRedo'')');
 
% Re-arrange the Undo/Redo buttons  
jToolbar = get(get(hToolbar,'JavaContainer'),'ComponentPeer');
jButtons = jToolbar.getComponents;
for buttonIdx = length(jButtons)-3 : -1 : 7  % end-to-front
   jToolbar.setComponentZOrder(jButtons(buttonIdx), buttonIdx+1);
end
jToolbar.setComponentZOrder(jButtons(end-2), 5);    % Separator
jToolbar.setComponentZOrder(jButtons(end-1), 6);    % Undo
jToolbar.setComponentZOrder(jButtons(end), 7);      % Redo
jToolbar.revalidate;
 
% Retrieve redo/undo object
undoObj = getappdata(gcf,'uitools_FigureToolManager');
if isempty(undoObj)
   undoObj = uitools.FigureToolManager(gcf);
   setappdata(gcf,'uitools_FigureToolManager',undoObj);
end
 
% Populate Undo actions drop-down list
jUndo = get(hUndo,'JavaContainer');
jMenu = get(jUndo,'MenuComponent');
undoActions = get(undoObj.CommandManager.UndoStack,'Name');
jMenu.removeAll;
for actionIdx = length(undoActions) : -1 : 1    % end-to-front
    jActionItem = jMenu.add(undoActions(actionIdx));
    set(jActionItem, 'ActionPerformedCallback', @myUndoCallbackFcn);
end
jToolbar.revalidate;
 
% Drop-down callback function
function myUndoCallbackFcn(jActionItem,hEvent)
    % user processing needs to be placed here
end  % myUndoCallbackFcn

undo/redo buttons implemented using uisplittool

undo/redo buttons implemented using uisplittool

In a real-world application, the code-segment above that populated the drop-down list would be placed within the slider’s test_uiundo() callback function, and we would set a similar drop-down for the hRedu button. In addition, we would dynamically modify the button tooltips. As a final customization, we could modify the figure’s main menu. Menu customization will be discussed in a future separate set of articles.

Have you used uisplittool or uitogglesplittool in your GUI? If so, please tell us what use you have made of them, in a comment below.

]]>
https://undocumentedmatlab.com/blog_old/uisplittool-uitogglesplittool-callbacks/feed 3
uisplittool & uitogglesplittoolhttps://undocumentedmatlab.com/blog_old/uisplittool-uitogglesplittool https://undocumentedmatlab.com/blog_old/uisplittool-uitogglesplittool#comments Thu, 09 Dec 2010 00:06:33 +0000 https://undocumentedmatlab.com/?p=1994 Related posts:
  1. uiundo – Matlab’s undocumented undo/redo manager The built-in uiundo function provides easy yet undocumented access to Matlab's powerful undo/redo functionality. This article explains its usage....
  2. uisplittool & uitogglesplittool callbacks Matlab's undocumented uisplittool and uitogglesplittool are powerful toolbar controls - this article explains how to customize their behavior...
  3. Customizing uiundo This article describes how Matlab's undocumented uiundo undo/redo manager can be customized...
  4. Customizing the standard figure toolbar, menubar The standard figure toolbar and menubar can easily be modified to include a list of recently-used files....
]]>
Matlab 7.6 (R2008a) and onward contain a reference to uisplittool and uitogglesplittool in the javacomponent.m and %matlabroot%/bin/registry/hg.xml files. These are reported as built-in functions by the which function, although they have no corresponding m-file as other similar built-in functions (note the double ‘t’, as in split-tool):

>> which uisplittool
built-in (C:\Matlab\R2010b\toolbox\matlab\uitools\uisplittool)

These uitools are entirely undocumented, even today (R2010b). They puzzled me for a very long time. An acute reader (Jeremy Raymonds) suggested they are related to toolbars, like other uitools such as the uipushtool and uitoggletool. This turned out to be the missing clue that unveiled these useful tools:

So what are uisplittool and uitogglesplittool?

Both uisplittool and uitogglesplittool are basic Handle-Graphics building blocks used in Matlab toolbars, similarly to the well-documented uipushtool and uitoggletool.

uisplittool presents a simple drop-down, whereas uitogglesplittool presents a drop-down that is also selectable.

The Publish and Run controls on the Matlab Editor’s toolbar are examples of uisplittool, and so are the Brush / Select-Data control on the figure toolbar, and the plot-selection drop-down on the Matlab Desktop’s Workspace toolbar:

uisplittool in action in the Matlab Desktop

uisplittool in action in the Matlab Desktop

Adding uisplittool and uitogglesplittool to a toolbar

Adding a uisplittool and uitogglesplittool to a toolbar is done in a similar manner to adding uipushtools and uitoggletools:

hToolbar = findall(gcf,'tag','FigureToolBar');
hUndo=uisplittool('parent',hToolbar);       % uisplittool
hRedo=uitogglesplittool('parent',hToolbar); % uitogglesplittool

Like uipushtool and uitoggletool, uisplittool and uitogglesplittool also have unique Type property values, ‘uisplittool’ and ‘uitogglesplittool’ respectively. The handles can also be tested using the built-in isa function:

>> isa(handle(hUndo),'uisplittool')   % or: 'uitogglesplittool'
ans =
     1
>> class(handle(hUndo))
ans =
uisplittool

Just as with uipushtools and uitoggletools, the new buttons have an empty button-face appearance, until we fix their CData, Tooltip and similar settable properties:

% Load the Redo icon
icon = fullfile(matlabroot,'/toolbox/matlab/icons/greenarrowicon.gif');
[cdata,map] = imread(icon);
 
% Convert white pixels into a transparent background
map(find(map(:,1)+map(:,2)+map(:,3)==3)) = NaN;
 
% Convert into 3D RGB-space
cdataRedo = ind2rgb(cdata,map);
cdataUndo = cdataRedo(:,[16:-1:1],:);
 
% Add the icon (and its mirror image = undo) to latest toolbar
set(hUndo, 'cdata',cdataUndo, 'tooltip','undo','Separator','on', ...
           'ClickedCallback','uiundo(gcbf,''execUndo'')');
set(hRedo, 'cdata',cdataRedo, 'tooltip','redo', ...
           'ClickedCallback','uiundo(gcbf,''execRedo'')');

User-created uisplittool & uitogglesplittool toolbar buttons

User-created uisplittool & uitogglesplittool toolbar buttons

Note that the controls can be created with these properties in a single command:

hUndo = uisplittool('parent',hToolbar, 'cdata',cdataRedo, ...);

Re-arranging the toolbar controls placement

Let us now re-arrange our toolbar buttons. Unfortunately, a bug causes uisplittools and uitogglesplittools to always be placed flush-left when the toolbar’s children are re-arranged (anyone at TMW reading this in time for the R2011a bug-parade selection?).

So, we can’t re-arrange the buttons at the HG-children level. Luckily, we can re-arrange directly at the Java level (note that until now, the entire discussion of uisplittool and uitogglesplittool was purely Matlab-based):

jToolbar = get(get(hToolbar,'JavaContainer'),'ComponentPeer');
jButtons = jToolbar.getComponents;
for buttonId = length(jButtons)-3 : -1 : 7  % end-to-front
   jToolbar.setComponentZOrder(jButtons(buttonId), buttonId+1);
end
jToolbar.setComponentZOrder(jButtons(end-2), 5);   % Separator
jToolbar.setComponentZOrder(jButtons(end-1), 6);   % Undo
jToolbar.setComponentZOrder(jButtons(end), 7);     % Redo
jToolbar.revalidate;

Re-arranged uisplittool & uitogglesplittool toolbar buttons

Re-arranged uisplittool & uitogglesplittool toolbar buttons
(not as simple as it may sound)

Next week, I will combine the information in this article, with last year’s articles about uiundo, and show how we can create a dynamic figure toolbar drop-down of undo/redo events. Here is a preview to whet your appetite:

undo/redo buttons implemented using uisplittool

undo/redo buttons implemented using uisplittool

]]>
https://undocumentedmatlab.com/blog_old/uisplittool-uitogglesplittool/feed 9
Uitab customizationshttps://undocumentedmatlab.com/blog_old/uitab-customizations https://undocumentedmatlab.com/blog_old/uitab-customizations#comments Wed, 17 Nov 2010 18:00:16 +0000 https://undocumentedmatlab.com/?p=1959 Related posts:
  1. Figure toolbar components Matlab's toolbars can be customized using a combination of undocumented Matlab and Java hacks. This article describes how to access existing toolbar icons and how to add non-button toolbar components....
  2. Customizing uitree This article describes how to customize Matlab GUI tree controls created using the undocumented uitree function...
  3. Customizing uitree nodes – part 2 This article shows how Matlab GUI tree nodes can be customized with checkboxes and similar controls...
  4. Uitab colors, icons and images Matlab's semi-documented tab panels can be customized using some undocumented hacks...
]]>
This article concludes my planned series on Matlab’s built-in semi-documented tab-panel functionality. In previous article I have shown how Matlab’s uitab and uitabgroup functions can be used to present tabbed contents, and how icon images can be attached to tabs using their undocumented underlying Java component. Today I will show other customizations that can be done to tabs.

Disabling tabs

Our first customization is to disable particular tabs. We start with a basic tab group, and get the underlying Java component:

% Prevent an annoying warning msg
warning off MATLAB:uitabgroup:OldVersion
 
% Prepare a tab-group consisting of two tabs
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)');
 
% Get the underlying Java reference (use hidden property)
jTabGroup = getappdata(handle(hTabGroup),'JTabbedPane');

Remember that Java uses 0-based indexing so tab #1 is actually the second tab. Let’s disable it by using the Java object’s setEnabledAt() method:

jTabGroup.setEnabledAt(1,false);  % disable only tab #1 (=second tab)
jTabGroup.setEnabled(false);  % disable all tabs
jTabGroup.setEnabled(true);  % re-enable all tabs (except tab #1)

A disabled tab

A disabled tab

Note that setting the property value for a specific tab overrides the value set for ALL tabs, despite the fact that setEnabled is called after setEnabledAt.

Look-and-Feel

Unlike some other controls, tabs have distinctly different appearances in different Look & Feels. Take a look at Plastic3DLookAndFeel, NimbusLookAndFeel and MetalLookAndFeel for tab panels that look distinctly different and more stylish than the WindowsLookAndFeel shown above.


WindowsLookAndFeel

WindowsLookAndFeel

WindowsClassicLookAndFeel

WindowsClassicLookAndFeel


Plastic3DLookAndFeel

Plastic3DLookAndFeel

MotifLookAndFeel

MotifLookAndFeel


MetalLookAndFeel

MetalLookAndFeel

NimbusLookAndFeel

NimbusLookAndFeel


Other customizations

There are other things we can customize, such as setting mnemonics (keyboard shortcuts), etc. – refer to the official documentation or any good textbook about Java Swing.

Tab callbacks are the same as the standard Swing components callbacks, except for StateChangedCallback, which is automatically linked to the internal function that synchronizes between the Java tab group and the Matlab uicontainers (in other words: it’s not a good idea to mess with it…).

Some jTabGroup functions that work well with standard JTabbedPane fail with uitabgroup: For example, jTabGroup.setIconAt or setTabLayoutPolicy. I am unsure of the reason for this. Other limitations with uitabgroup are a reported problem when compiling any GUI that includes it; a reported bug when reordering tabs; a reported problem rendering some graphic object properties (e.g., clipping); and a reported problem in displaying tabs containing ActiveX or Java objects (plus suggested solutions). Interested readers can fix all these issues by modifying the m-files in the folders %matlabroot%/toolbox/matlab/@uitools/@uitabgroup and /@uitools/@uitab. At least some of these problems are fixed as of R2010a.

Readers might also be interested in the Yet Another Layout Manager utility. This utility directly uses Swing’s JTabbedPane object to implement tab panels, essentially mimicking the built-in uitab/uitabgroup functions.

This concludes my series on Matlab’s uitab. Any other specific customizations you are interested in? Any nice variation of your own? Please do share your thoughts in a comment.

]]>
https://undocumentedmatlab.com/blog_old/uitab-customizations/feed 9
Uitab colors, icons and imageshttps://undocumentedmatlab.com/blog_old/uitab-colors-icons-images https://undocumentedmatlab.com/blog_old/uitab-colors-icons-images#comments Wed, 10 Nov 2010 18:00:01 +0000 https://undocumentedmatlab.com/?p=1955 Related posts:
  1. Figure toolbar components Matlab's toolbars can be customized using a combination of undocumented Matlab and Java hacks. This article describes how to access existing toolbar icons and how to add non-button toolbar components....
  2. Customizing uitree nodes – part 1 This article describes how to customize specific nodes of Matlab GUI tree controls created using the undocumented uitree function...
  3. Customizing uitree nodes – part 2 This article shows how Matlab GUI tree nodes can be customized with checkboxes and similar controls...
  4. Uitable sorting Matlab's uitables can be sortable using simple undocumented features...
]]>
A few months ago I published a post about Matlab’s semi-documented tab-panel functionality, where I promised a follow-up article on tab customizations. A reader of this blog asked a related question earlier today, so I decided it’s about time I fulfilled this promise.

As with most Matlab controls, the underlying Java component enables far greater customization than possible using plain Matlab. Today I will show three specific customizations. We start with a basic tab group, and get the underlying Java component:

% Prevent an annoying warning msg
warning off MATLAB:uitabgroup:OldVersion
 
% Prepare a tab-group consisting of two tabs
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)');
 
% Get the underlying Java reference (use hidden property)
jTabGroup = getappdata(handle(hTabGroup),'JTabbedPane');

Foreground & background tab colors

We can set the tab font color using setForeground() and setForegroundAt(), or via HTML. Note that setForegroundAt() overrides anything set by setForeground(). Also remember that Java uses 0-based indexing so tab #1 is actually the second tab:

% Equivalent manners to set a red tab foreground:
jTabGroup.setForegroundAt(1,java.awt.Color(1.0,0,0)); % tab #1
jTabGroup.setTitleAt(1,'<html><font color="red"><i>Panel 2');
jTabGroup.setForeground(java.awt.Color.red);

Unfortunately, the corresponding setBackgroundAt(tabIndex,color) method has no visible effect, and the Matlab-extended tabs keep their white/gray backgrounds. A similar attempt to modify the tab’s BackgroundColor property fails, since Matlab made this property unmodifiable (=’none’). A simple solution is to use a CSS background:

% Equivalent manners to set a yellow tab background:
jTabGroup.setTitleAt(0,'<html><div style="background:#ffff00;">Panel 1');
jTabGroup.setTitleAt(0,'<html><div style="background:yellow;">Panel 1');

uitabgroup with non-default forground and background tab colors and fonts

uitabgroup with non-default forground and background tab colors and fonts

We can set the foreground text color using the CSS color directive. Similarly, we can also set a background gradient image for the tabs, using the CSS background-image directive. Which leads us to our next customization:

Icon images

Icons and sub-components can be added to the tabs. Unfortunately, for some reason that I do not fully understand, jTabGroup.setIconAt() has no apparent effect. The solution is to set our own custom control as the requested tab, and add our icon (or other customizations) to it. Here is a simple example:

% Add an icon to tab #1 (=second tab)
icon = javax.swing.ImageIcon('C:\Yair\save.gif');
jLabel = javax.swing.JLabel('Tab #2');
jLabel.setIcon(icon);
jTabGroup.setTabComponentAt(1,jLabel);	% Tab #1 = second tab
 
% Note: icon is automatically grayed when label is disabled
jLabel.setEnabled(false);
jTabGroup.setEnabledAt(1,false);  % disable only tab #1

tab with a custom icon (enabled)
tab with a custom icon (enabled)

tab with a custom icon (enabled & disabled)

Close buttons

Now let’s try a more complex example, of adding a close (‘x’) button to one of the tabs. Generalizing this code snippet is left as an exercise to the reader:

% First let's load the close icon
jarFile = fullfile(matlabroot,'/java/jar/mwt.jar');
iconsFolder = '/com/mathworks/mwt/resources/';
iconURI = ['jar:file:/' jarFile '!' iconsFolder 'closebox.gif'];
icon = javax.swing.ImageIcon(java.net.URL(iconURI));
 
% Now let's prepare the close button: icon, size and callback
jCloseButton = handle(javax.swing.JButton,'CallbackProperties');
jCloseButton.setIcon(icon);
jCloseButton.setPreferredSize(java.awt.Dimension(15,15));
jCloseButton.setMaximumSize(java.awt.Dimension(15,15));
jCloseButton.setSize(java.awt.Dimension(15,15));
set(jCloseButton, 'ActionPerformedCallback',@(h,e)delete(tab2));
 
% Now let's prepare a tab panel with our label and close button
jPanel = javax.swing.JPanel;	% default layout = FlowLayout
set(jPanel.getLayout, 'Hgap',0, 'Vgap',0);  % default gap = 5px
jLabel = javax.swing.JLabel('Tab #2');
jPanel.add(jLabel);
jPanel.add(jCloseButton);
 
% Now attach this tab panel as the tab-group's 2nd component
jTabGroup.setTabComponentAt(1,jPanel);	% Tab #1 = second tab

tab with an attached close button

tab with an attached close button

Next week’s article will conclude the series on Matlab’s uitab. Any particular customization you are interested in? Please do post a comment.

Addendum Oct 3 2014: the uitab and uitabgroup functions have finally become fully supported and documented in Matlab version 8.4 (R2014b). However, the Java-based customizations shown in this article are still unsupported and undocumented, although they remain practically unchanged from what I’ve described in this article, four years earlier.

]]>
https://undocumentedmatlab.com/blog_old/uitab-colors-icons-images/feed 39
Customizing uitree nodes – part 2https://undocumentedmatlab.com/blog_old/customizing-uitree-nodes-2 https://undocumentedmatlab.com/blog_old/customizing-uitree-nodes-2#comments Wed, 01 Sep 2010 08:00:57 +0000 https://undocumentedmatlab.com/?p=1850 Related posts:
  1. Figure toolbar components Matlab's toolbars can be customized using a combination of undocumented Matlab and Java hacks. This article describes how to access existing toolbar icons and how to add non-button toolbar components....
  2. Uitab colors, icons and images Matlab's semi-documented tab panels can be customized using some undocumented hacks...
  3. Customizing uitree This article describes how to customize Matlab GUI tree controls created using the undocumented uitree function...
  4. Customizing uitree nodes – part 1 This article describes how to customize specific nodes of Matlab GUI tree controls created using the undocumented uitree function...
]]>
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 https://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.

]]>
https://undocumentedmatlab.com/blog_old/customizing-uitree-nodes-2/feed 61
Customizing uitree nodes – part 1https://undocumentedmatlab.com/blog_old/customizing-uitree-nodes https://undocumentedmatlab.com/blog_old/customizing-uitree-nodes#comments Wed, 25 Aug 2010 18:00:20 +0000 https://undocumentedmatlab.com/?p=1835 Related posts:
  1. Uitab colors, icons and images Matlab's semi-documented tab panels can be customized using some undocumented hacks...
  2. Figure toolbar components Matlab's toolbars can be customized using a combination of undocumented Matlab and Java hacks. This article describes how to access existing toolbar icons and how to add non-button toolbar components....
  3. Customizing uitree nodes – part 2 This article shows how Matlab GUI tree nodes can be customized with checkboxes and similar controls...
  4. Customizing uitree This article describes how to customize Matlab GUI tree controls created using the undocumented uitree function...
]]>
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.

]]>
https://undocumentedmatlab.com/blog_old/customizing-uitree-nodes/feed 21
Customizing uitreehttps://undocumentedmatlab.com/blog_old/customizing-uitree https://undocumentedmatlab.com/blog_old/customizing-uitree#comments Wed, 18 Aug 2010 18:00:15 +0000 https://undocumentedmatlab.com/?p=1808 Related posts:
  1. Figure toolbar components Matlab's toolbars can be customized using a combination of undocumented Matlab and Java hacks. This article describes how to access existing toolbar icons and how to add non-button toolbar components....
  2. Tab panels – uitab and relatives This article describes several undocumented Matlab functions that support tab-panels...
  3. uitree This article describes the undocumented Matlab uitree function, which displays data in a GUI tree component...
  4. Uitab colors, icons and images Matlab's semi-documented tab panels can be customized using some undocumented hacks...
]]>
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.

]]>
https://undocumentedmatlab.com/blog_old/customizing-uitree/feed 43
uitreehttps://undocumentedmatlab.com/blog_old/uitree https://undocumentedmatlab.com/blog_old/uitree#comments Wed, 11 Aug 2010 18:00:40 +0000 https://undocumentedmatlab.com/?p=1801 Related posts:
  1. Tab panels – uitab and relatives This article describes several undocumented Matlab functions that support tab-panels...
  2. Matlab and the Event Dispatch Thread (EDT) The Java Swing Event Dispatch Thread (EDT) is very important for Matlab GUI timings. This article explains the potential pitfalls and their avoidance using undocumented Matlab functionality....
  3. Matlab layout managers: uicontainer and relatives Matlab contains a few undocumented GUI layout managers, which greatly facilitate handling GUI components in dynamically-changing figures....
  4. The javacomponent function Matlab's built-in javacomponent function can be used to display Java components in Matlab application - this article details its usages and limitations...
]]>
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.

]]>
https://undocumentedmatlab.com/blog_old/uitree/feed 78
Tab panels – uitab and relativeshttps://undocumentedmatlab.com/blog_old/tab-panels-uitab-and-relatives https://undocumentedmatlab.com/blog_old/tab-panels-uitab-and-relatives#comments Wed, 23 Jun 2010 12:43:16 +0000 https://undocumentedmatlab.com/?p=1635 Related posts:
  1. uitree This article describes the undocumented Matlab uitree function, which displays data in a GUI tree component...
  2. Context-Sensitive Help Matlab has a hidden/unsupported built-in mechanism for easy implementation of context-sensitive help...
  3. Uitable sorting Matlab's uitables can be sortable using simple undocumented features...
  4. Customizing Matlab labels Matlab's text uicontrol is not very customizable, and does not support HTML or Tex formatting. This article shows how to display HTML labels in Matlab and some undocumented customizations...
]]>
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

Edit Oct 27 2010: R2010b made a few changes to the hTabGroup properties: SelectedTab has been added (holds the handle of the selected tab, rather than its index as SelectedIndex; note that SelectedTab was added as a hidden property for some unknown reason, probably a programming mistake); the tab BackgroundColor cannot be modified (I’ll show how to bypass this limitation in a near-future article); SelectionChangeFcn callback and the SelectionChanged event have changed their names to SelectionChangeCallback and SelectionChange respectively. Note that this is one of the very rare occasions in which MathWorks have taken the trouble to notify users about changes to one of their undocumented/unsupported functions. They should be commended for this since it helps us Matlab users make better use of the product.

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 (this alternative only works on R2014a or earlier!). 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','JTabbedPane');
 
% A direct alternative for getting jTabGroup (only works up to R2014a!)
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?

Addendum Oct 3 2014: the uitab and uitabgroup functions have finally become fully supported and documented in Matlab version 8.4 (R2014b). They remain practically unchanged from what I’ve described in this article, more than four years earlier.

]]>
https://undocumentedmatlab.com/blog_old/tab-panels-uitab-and-relatives/feed 116
Customizing uiundohttps://undocumentedmatlab.com/blog_old/customizing-uiundo https://undocumentedmatlab.com/blog_old/customizing-uiundo#comments Thu, 05 Nov 2009 00:29:13 +0000 https://undocumentedmatlab.com/?p=708 Related posts:
  1. uiundo – Matlab’s undocumented undo/redo manager The built-in uiundo function provides easy yet undocumented access to Matlab's powerful undo/redo functionality. This article explains its usage....
  2. Matlab’s HG2 mechanism HG2 is presumably the next generation of Matlab graphics. This article tries to explore its features....
  3. Uitable sorting Matlab's uitables can be sortable using simple undocumented features...
  4. Handle Graphics Behavior HG behaviors are an important aspect of Matlab graphics that enable custom control of handle functionality. ...
]]>
Last week I discussed uiundo – Matlab’s undocumented undo/redo manager. Today, I will show how this object can be customized for some specific needs. However, we first need to understand a little more about how uiundo works beneath the hood.

Matlab stores all of a figure’s undo/redo data in a hidden figure object, referenced by getappdata(hFig,’uitools_FigureToolManager’). This means that by default uiundo works at the figure level, rather than the application level or the GUI component level. If we wish to modify this default behavior, we need to programmatically inspect and filter the undo/redo actions stack based on the action source. Read below to see how this can be done.

The hidden uitools_FigureToolManager object, defined in %MATLABROOT%\toolbox\matlab\uitools\@uiundo\, uses a stack to store instances of the undo/redo cmd data structure introduced in last week’s post:

% Retrieve redo/undo object
undoObj = getappdata(hFig,'uitools_FigureToolManager');
if isempty(undoObj)
   try
      % R2014a and earlier
      undoObj = uitools.FigureToolManager(hFig);
   catch
      % R2014b and newer
      undoObj = matlab.uitools.internal.FigureToolManager(hFig);
   end
   setappdata(hFig,'uitools_FigureToolManager',undoObj);
end
 
>> get(undoObj)
    CommandManager: [1x1 uiundo.CommandManager]
            Figure: [1x1 figure]
        UndoUIMenu: [1x1 uimenu]
        RedoUIMenu: [1x1 uimenu]

There are several interesting things we can do with this undoObj. First, let’s modify the main-menu items (I will discuss menu customization in more detail in another post):

% Modify the main menu item (similarly for redo/undo)
if ~isempty(undoObj.RedoUIMenu)
   undoObj.RedoUIMenu.Position =1; %default=2 (undo above redo)
   undoObj.RedoUIMenu.Enable = 'off';     % default='on'
   undoObj.RedoUIMenu.Checked = 'on';     % default='off'
   undoObj.RedoUIMenu.ForegroundColor = [1,0,0];  % =red
end
if ~isempty(undoObj.UndoUIMenu)
   undoObj.UndoUIMenu.Label = '<html><b><i>Undo action';
   % Note: &Undo underlines 'U' and adds a keyboard accelerator
   % but unfortunately only if the label is non-HTML ...
   undoObj.UndoUIMenu.Separator = 'on';   % default='off'
   undoObj.UndoUIMenu.Checked = 'on';     % default='off'
   undoObj.UndoUIMenu.ForegroundColor = 'blue'; % default=black
end
</i></b></html>

Menu before customization

Menu after customization

Figure menu before and after customization

Now, let’s take a look at undoObj’s CommandManager child (the Figure child object is simply handle(hFig), and so is not very interesting):

>> undoObj.CommandManager.get
             UndoStack: [13x1 uiundo.FunctionCommand]
             RedoStack: [1x1 uiundo.FunctionCommand]
    MaxUndoStackLength: []
               Verbose: []
 
>> undoObj.CommandManager.UndoStack(end).get
             Parent: []
       MCodeComment: []
               Name: 'slider update (0.48 to 0.38)'
           Function: @internal_update
           Varargin: {[53.0037841796875]  [0.38]  [1x1 double]}
    InverseFunction: @internal_update
    InverseVarargin: {[53.0037841796875]  [0.48]  [1x1 double]}

This looks familiar: In fact, it is exactly the cmd data structure being passed to the uiundo function, with the additional (apparently unused) properties Parent and MCodeComment. CommandManager‘s UndoStack and RedoStack child objects contain all stored undo/redo actions such that the latest action is at the end of these arrays. In the snippet above, there are 13 undo-able actions, with the latest action in UndoStack(end). UndoStack and RedoStack have the same structure:

  • Name contains the action description (presented in the figure’s menu)
  • Function is the function handle that will be invoked if the action is redone
  • Varargin are the arguments passed to Function during redo
  • InverseFunction is the function handle that will be invoked if the action is undone
  • InverseVarargin are the arguments passed to InverseFunction during undo
  • Parent and MCodeComment – I could not determine what these are used for

We can inspect the latest undo/redo actions, without activating them, by using CommandManager‘s peekundo() and peekredo() methods (which return empty [] if no undo/redo action is available):

>> undoObj.CommandManager.peekredo.get % first check if isempty
             Parent: []
       MCodeComment: []
               Name: 'slider update (0.38 to 0.28)'
           Function: @internal_update
           Varargin: {[53.0037841796875]  [0.28]  [1x1 double]}
    InverseFunction: @internal_update
    InverseVarargin: {[53.0037841796875]  [0.38]  [1x1 double]}
 
>> undoObj.CommandManager.peekundo.get
             Parent: []
       MCodeComment: []
               Name: 'slider update (0.48 to 0.38)'
           Function: @internal_update
           Varargin: {[53.0037841796875]  [0.38]  [1x1 double]}
    InverseFunction: @internal_update
    InverseVarargin: {[53.0037841796875]  [0.48]  [1x1 double]}
 
>> undoObj.CommandManager.peekundo.Name
ans =
slider update (0.48 to 0.38)

We can undo/redo the latest action (last element of the UndoStack/RedoStack) by invoking CommandManager‘s undo()/redo() methods. This is actually what uiundo is doing behind the scenes when it is called with the ‘execUndo’ and ‘execRedo’ arguments:

undoObj.CommandManager.undo;
undoObj.CommandManager.redo;

We can clear the entire actions stack by using CommandManager‘s empty() method. This can be useful, for example, after a ‘Save’ or ‘Apply’ operation in our GUI:

undoObj.CommandManager.empty;

If we set CommandManager‘s Verbose property to any non-empty value, debug information is spilled onto the Command Window when new uiundo actions are added:

>> undoObj.CommandManager.Verbose = 1;
 
% now move the slider and see the debug info below:
internal_update(h_uicontrol, [0.48,], h_uicontrol); % Called by slider update (0.28 to 0.48)
internal_update(h_uicontrol, [0.58,], h_uicontrol); % Called by slider update (0.48 to 0.58)

Finally, CommandManager uses its MaxUndoStackLength property to limit the size of the undo/redo stacks. This property is defined as read-only in %matlabroot%\toolbox\matlab\uitools\@uiundo\@CommandManager\schema.m line #12, so if you wish to programmatically modify this property from its default value of empty (=unlimited), you will need to comment out that line.

]]>
https://undocumentedmatlab.com/blog_old/customizing-uiundo/feed 9
uiundo – Matlab’s undocumented undo/redo managerhttps://undocumentedmatlab.com/blog_old/uiundo-matlab-undocumented-undo-redo-manager https://undocumentedmatlab.com/blog_old/uiundo-matlab-undocumented-undo-redo-manager#comments Thu, 29 Oct 2009 22:11:11 +0000 https://undocumentedmatlab.com/?p=688 Related posts:
  1. Customizing uiundo This article describes how Matlab's undocumented uiundo undo/redo manager can be customized...
  2. uisplittool & uitogglesplittool Matlab's undocumented uisplittool and uitogglesplittool are powerful controls that can easily be added to Matlab toolbars - this article explains how...
  3. Adding dynamic properties to graphic handles It is easy and very useful to attach dynamic properties to Matlab graphics objects in run-time. ...
  4. New information on HG2 More information on Matlab's new HG2 object-oriented handle-graphics system...
]]>
Whenever we have a Matlab GUI containing user-modifiable controls (edit boxes, sliders, toggle buttons etc.), we may wish to include an undo/redo feature. This would normally be a painful programming task. Luckily, there is an undocumented built-in Matlab support for this functionality via the uiundo function. Note that uiundo and its functionality is not Java-based but rather uses Matlab’s classes and the similarly-undocumented schema-based object-oriented approach.

A couple of months ago, I explained how to customize the figure toolbar. In that article, I used the undocumented uiundo function as a target for the toolbar customization and promised to explain its functionality later. I would now like to explain uiundo and its usage.

The uiundo function is basically an accessor for Matlab’s built-in undo/redo manager object. It is located in the uitools folder (%MATLABROOT%\toolbox\matlab\uitools) and its @uiundo sub-folder. To use uiundo, simply define within each uicontrol’s callback function (where we normally place our application GUI logic) the name of the undo/redo action, what should be done to undo the action, and what should be done if the user wished to redo the action after undoing it. uiundo then takes care of adding this data to the figure’s undo/redo options under Edit in the main figure menu.

For example, let’s build a simple GUI consisting of a slider that controls the value of an edit box:

hEditbox = uicontrol('style','edit', 'position',[20,60,40,40]); 
set(hEditbox, 'Enable','off', 'string','0');
hSlider = uicontrol('style','slider','userdata',hEditbox);
callbackStr = 'set(get(gcbo,''userdata''),''string'',num2str(get(gcbo,''value'')))';
set(hSlider,'Callback',callbackStr);

Simple GUI with slider update of a numeric value

Simple GUI with slider update of a numeric value

Now, let’s attach undo/redo actions to the slider’s callback. First, place the following in test_uiundo.m:

% Main callback function for slider updates
function test_uiundo(varargin)
 
  % Update the edit box with the new value
  hEditbox = get(gcbo,'userdata');
  newVal = get(gcbo,'value');
  set(hEditbox,'string',num2str(newVal));
 
  % Retrieve and update the stored previous value
  oldVal = getappdata(gcbo,'oldValue');
  if isempty(oldVal),  oldVal=0;  end
  setappdata(gcbo,'oldValue',newVal);
 
  % Prepare an undo/redo action
  cmd.Name = sprintf('slider update (%g to %g)',oldVal,newVal);
 
  % Note: the following is not enough since it only
  %       updates the slider and not the editbox...
  %cmd.Function        = @set;                  % Redo action
  %cmd.Varargin        = {gcbo,'value',newVal};
  %cmd.InverseFunction = @set;                  % Undo action
  %cmd.InverseVarargin = {gcbo,'value',oldVal};
 
  % This takes care of the update problem...
  cmd.Function        = @internal_update;       % Redo action
  cmd.Varargin        = {gcbo,newVal,hEditbox};
  cmd.InverseFunction = @internal_update;       % Undo action
  cmd.InverseVarargin = {gcbo,oldVal,hEditbox};
 
  % Register the undo/redo action with the figure
  uiundo(gcbf,'function',cmd);
end
 
% Internal update function to update slider & editbox
function internal_update(hSlider,newValue,hEditbox)
  set(hSlider,'value',newValue);
  set(hEditbox,'string',num2str(newValue));
end

And now let’s point the slider’s callback to our new function:

>> set(hSlider,'Callback',@test_uiundo);

Undo/redo functionality integrated in the figure

Undo/redo functionality integrated in the figure

We can also invoke the current Undo and Redo actions programmatically, by calling uiundo with the ‘execUndo’ and ‘execRedo’ arguments:

uiundo(hFig,'execUndo');
uiundo(hFig,'execRedo');

When invoking the current Undo and Redo actions programmatically, we can ensure that this action would be invoked only if it is a specific action that is intended:

uiundo(hFig,'execUndo','Save data');  % should equal cmd.Name

We can use this approach to attach programmatic undo/redo actions to new toolbar or GUI buttons. The code for this was given in the above-mentioned article. Here is the end-result:


Undo/redo functionality integrated in the figure toolbar

Undo/redo functionality integrated in the figure toolbar

Undo/redo functionality integrated in the figure toolbar


In my next post, due next week, I will explore advanced customizations of this functionality.

]]>
https://undocumentedmatlab.com/blog_old/uiundo-matlab-undocumented-undo-redo-manager/feed 2
Undocumented mouse pointer functionshttps://undocumentedmatlab.com/blog_old/undocumented-mouse-pointer-functions https://undocumentedmatlab.com/blog_old/undocumented-mouse-pointer-functions#comments Thu, 24 Sep 2009 16:48:16 +0000 https://undocumentedmatlab.com/?p=601 Related posts:
  1. Context-Sensitive Help Matlab has a hidden/unsupported built-in mechanism for easy implementation of context-sensitive help...
  2. Tab panels – uitab and relatives This article describes several undocumented Matlab functions that support tab-panels...
  3. uitree This article describes the undocumented Matlab uitree function, which displays data in a GUI tree component...
  4. Customizing menu items part 1 Matlab menus can be customized in a variety of undocumented manners - first article of a series. ...
]]>
Matlab contains several well-documented functions and properties dealing with the mouse pointer. However, for some reason, some very-useful functions have remained undocumented and unsupported despite having a very long history (as far back as Matlab 6, a decade ago).

getptr, setptr, moveptr and overobj are all semi-documented functions (help section available, but online doc and official support not) which are used for internal Matlab purposes and relate to the mouse pointer. All these files are pure-Matlab non-Java files, which can be edited and modified. getptr and setptr (%Matlabroot\toolbox\matlab\uitools\getptr.m and setptr.m) access the pointer shape for a figure; moveptr (%Matlabroot\toolbox\shared\controllib\moveptr.m) moves the pointer across the screen; overobj (%Matlabroot\toolbox\matlab\uitools\overobj.m) determines which figure component is currently beneath the pointer.

getptr and setptr

While undocumented Java code is needed for setting component-specific pointer shapes, figure-wide shapes can be set using pure-Matlab. Setting the mouse pointer shape is normally achieved by modifying the figure’s Pointer property, which is fully documented. The following pointer shapes are supported: ‘arrow’ (the default Matlab pointer), ‘crosshair’, ‘fullcrosshair’ (used for ginput), ‘ibeam’, ‘watch’, ‘topl’, ‘topr’, ‘botl’, ‘botr’, ‘left’, ‘top’, ‘right’, ‘bottom’, ‘circle’, ‘cross’, ‘fleur’, and ‘custom’. For example:

set(hFig, 'Pointer', 'crosshair');

Using setptr enables access to a far greater variety of pointer shapes, in addition to all the standard shapes above: ‘hand’, ‘hand1’, ‘hand2’, ‘closedhand’, ‘glass’, ‘glassplus’, ‘glassminus’, ‘lrdrag’, ‘ldrag’, ‘rdrag’, ‘uddrag’, ‘udrag’, ‘ddrag’, ‘add’, ‘addzero’, ‘addpole’, ‘eraser’, ‘help’, ‘modifiedfleur’, ‘datacursor’, and ‘rotate’. It also has a few entirely-undocumented shapes: ‘forbidden’, and ‘file’ (which expects a cursor data filepath as the following argument):

setptr(gcf, 'hand');
setptr(gcf, 'file', 'my137byteFile.data');

getptr returns a cell array of parameter name/value pairs that can be stored and later used to restore the pointer shape for a specified figure:

ptr = getptr(gcf);
% do some stuff...
set(gcf, ptr{:});

moveptr

moveptr is used to move the mouse pointer programmatically across a specific plot axes. This function is poorly and incorrectly documented and contains quite a few bugs (as of R2008b). However, with minor fixes and slight attention to usage, it can be quite useful.

The regular and fully documented/supported method of moving the mouse pointer across the screen is by modifying the root (0) handle’s PointerLocation property. In many cases we may wish to programmatically move the pointer from to a specific location in a plot axes. This can be done of course by computing the figure’s dimensions and position in screen pixel coordinates, and the internal figure components dimensions/position within the figure, and their internal components and so on, not forgetting to translate data or normalized coordinates into screen pixel units, and taking care of logarithmic and reverse axes. After adding all these up, and assuming we’ve made no mistake in the computation (no easy task), we can now set the root handle’s PointerLocation property.

Comes moveptr to the rescue:

moveptr accepts a handle(hAxes) as first parameter (note that handle(hAxes) must be passed, not hAxes!), and one of the following; either ‘init’ to initialize the move (creating a transformation from local axes data units to screen pixels), or ‘move’ followed by X,Y (axes data units) to actually move the mouse pointer. X and Y may well be outside the axes boundaries:

moveptr(handle(gca),'init');
moveptr(handle(gca),'move',-5,7);  % so easy

moveptr is only available in Matlab 7, not Matlab 6. moveptr also has a bug/limitation (fixed in R2008a) in that it expects the supplied axes to be a direct child of the figure. Finally, it accepts handle(hAxes) as first parameter – not the regular numeric hAxes handle as its help section would have us believe. These may not of course be the case in a more general case. Note that R2008a’s fix for the direct-figure-child limitation, using hgconvertunits (another semi-documented function), is incompatible with Matlab 6, which did not have this function. The fix for all these issues, which accepts both hAxes and handle(hAxes), removes the direct-figure-child limitation and also works on Matlab 6, is outlined below:

%% Moveptr replacement for Matlab 6 compatibility
function moveptr(hAx, x, y)
  % Compute normalized axis coordinates
  NormX = getNormCoord(hAx, 'x', x);
  NormY = getNormCoord(hAx, 'y', y);
 
  % Compute the new coordinates in screen units
  Transform = axis2Screen(hAx);
  NewLoc = Transform(1:2) + Transform(3:4) .* [NormX NormY];
 
  % Move the pointer
  set(0,'PointerLocation',NewLoc);
%end  % moveptr
 
%% Get normalized axis coordinates
function normCoord = getNormCoord(hAx, axName, curPos)
  limits = get(hAx, [axName 'Lim']);
  if strcmpi(get(hAx,[axName 'Scale']), 'log')
    normCoord = (log2(curPos) - log2(limits(1))) /diff(log2(limits));
  else
    normCoord = (curPos-limits(1)) / diff(limits);
  end
%end  % getNormCoord
 
%% Axis to screen coordinate transformation
function T = axis2Screen(ax)
  % computes a coordinate transformation T = [xo,yo,rx,ry] that
  % relates normalized axes coordinates [xa,ya] of point [xo,yo]
  % to its screen coordinate [xs,ys] (in the root units) by:
  %     xs = xo + rx * xa
  %     ys = yo + ry * ya
  % Note: this is a modified internal function within moveptr()
  % Get axes normalized position in figure
  T = getPos(ax,'normalized');
  % Loop all the way up the hierarchy to the root
  % Note: this fixes a bug in Matlab 7's moveptr implementation
  parent = get(ax,'Parent');
  while ~isempty(parent)
    % Transform normalized axis coords -> parent coords
    if isequal(parent,0)
      parentPos = get(0,'ScreenSize');  % Save screen units
    else
      parentPos = getPos(parent, 'normalized'); % Norm units
    end
    T(1:2) = parentPos(1:2) + parentPos(3:4) .* T(1:2);
    T(3:4) = parentPos(3:4) .* T(3:4);
    parent = get(parent,'Parent');
  end
%end  % axis2Screen

overobj and hittest

overobj is a related semi-documented function. It returns a handle to the first visible element beneath the mouse pointer that has visible handles (i.e., can be found with findobj , as opposed to hidden handles that can only be found using findall). The mandatory Type argument specifies the requested handle’s Type property value.

There are several overobj usage samples in CSSM. Here is an example for modifying the mouse cursor over axes:

% Modify mouse pointer over axes
hAxes = overobj('axes');
if ~isempty(hAxes)
    set(gcf,'Pointer','fleur');
else
    set(gcf,'Pointer','arrow');
end

A CSSM reader has noted that since overobj uses the findobj function, it is rather slow. Therefore, do not use overobj in a complex figure’s WindowButtonMotionFcn callback.

overobj has other annoying limitations: it only searches direct figure children, not inner descendants. Therefore, anything contained within a uipanel, uibuttongroup etc. cannot be found. Also, it assumes the root and figure units are both ‘pixel’: often they are not. Also, it only searches visible objects: hidden axes are not retrieved. Finally, it would be a great benefit to have an overobj variant in which the Type argument is optional, so the function would return the handle of the first object found, of whichever type. Here’s this variant overobj2, adapted from Matlab’s overobj. Note that overobj and overobj2 only work on objects having a Position property, and so cannot be used for axes plot children:

function h = overobj2(varargin)
%OVEROBJ2 Get handle of object that the pointer is over.
%   H = OVEROBJ2 searches all objects in the PointerWindow
%   looking for one that is under the pointer. Returns first
%   object handle it finds under the pointer, or empty matrix.
%
%   H = OVEROBJ2(FINDOBJ_PROPS) searches all objects which are
%   descendants of the figure beneath the pointer and that are
%   returned by FINDOBJ with the specified arguments.
%
%   Example:
%       h = overobj2('type','axes');
%       h = overobj2('flat','visible','on');
%
%   See also OVEROBJ, FINDOBJ
 
% Ensure root units are pixels
oldUnits = get(0,'units');
set(0,'units','pixels');
 
% Get the figure beneath the mouse pointer & mouse pointer pos
try
   fig = get(0,'PointerWindow');  % HG1: R2014a or older
catch
   fig = matlab.ui.internal.getPointerWindow;  % HG2: R2014b or newer
end
p = get(0,'PointerLocation');
set(0,'units',oldUnits);
 
% Look for quick exit (if mouse pointer is not over any figure)
if fig==0,  h=[]; return;  end
 
% Compute figure offset of mouse pointer in pixels
figPos = getpixelposition(fig);
x = (p(1)-figPos(1));
y = (p(2)-figPos(2));
 
% Loop over all figure descendants
c = findobj(get(fig,'Children'),varargin{:});
for h = c'
   % If descendant contains the mouse pointer position, exit
   r = getpixelposition(h);  % Note: cache this for improved performance
   if (x>r(1)) && (x<r(1)+r(3)) && (y>r(2)) && (y<r(2)+r(4))
      return
   end
end
h = [];


An alternative to overobj or overobj2 is to use the undocumented hittest built-in function – separate cases may dictate preferring one alternative to the other:

hObj = hittest(hFig);

p.s. – while most of Matlab’s undocumented stuff indeed lies in the Java domain, there are quite a few non-Java pearls to be exposed, as in this article. From time to time I will take time off from Java and describe these aspects.

]]>
https://undocumentedmatlab.com/blog_old/undocumented-mouse-pointer-functions/feed 33
Figure toolbar componentshttps://undocumentedmatlab.com/blog_old/figure-toolbar-components https://undocumentedmatlab.com/blog_old/figure-toolbar-components#comments Thu, 27 Aug 2009 16:31:36 +0000 https://undocumentedmatlab.com/?p=541 Related posts:
  1. Uitab colors, icons and images Matlab's semi-documented tab panels can be customized using some undocumented hacks...
  2. Customizing uitree nodes – part 2 This article shows how Matlab GUI tree nodes can be customized with checkboxes and similar controls...
  3. Customizing uitree This article describes how to customize Matlab GUI tree controls created using the undocumented uitree function...
  4. Customizing uitree nodes – part 1 This article describes how to customize specific nodes of Matlab GUI tree controls created using the undocumented uitree function...
]]>
Toolbars are by now a staple of modern GUI design. An unobtrusive list of small icons enables easy access to multiple application actions without requiring large space for textual descriptions. Unfortunately, the built-in documented support for the Matlab toolbars is limited to adding icon buttons via the uipushtool and uitoggletool functions, and new toolbars containing them via the uitoolbar function. In this post I will introduce several additional customizations that rely on undocumented features.

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

Accessing toolbar buttons – undo/redo

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

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

% Load the Redo icon
icon = fullfile(matlabroot,'/toolbox/matlab/icons/greenarrowicon.gif');
[cdata,map] = imread(icon);
 
% Convert white pixels into a transparent background
map(find(map(:,1)+map(:,2)+map(:,3)==3)) = NaN;
 
% Convert into 3D RGB-space
cdataRedo = ind2rgb(cdata,map);
cdataUndo = cdataRedo(:,[16:-1:1],:);

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

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

Undo/redo buttons

Undo/redo buttons

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

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

Undo/redo buttons in their expected positions

Undo/redo buttons in their expected positions

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

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

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

Adding non-button toolbar components – undo dropdown

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

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

Undo dropdown list

Undo dropdown list

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

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

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

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

]]>
https://undocumentedmatlab.com/blog_old/figure-toolbar-components/feed 48
Context-Sensitive Helphttps://undocumentedmatlab.com/blog_old/context-sensitive-help https://undocumentedmatlab.com/blog_old/context-sensitive-help#comments Wed, 05 Aug 2009 18:20:26 +0000 https://undocumentedmatlab.com/?p=491 Related posts:
  1. Tab panels – uitab and relatives This article describes several undocumented Matlab functions that support tab-panels...
  2. Customizing print setup Matlab figures print-setup can be customized to automatically prepare the figure for printing in a specific configuration...
  3. Inactive Control Tooltips & Event Chaining Inactive Matlab uicontrols cannot normally display their tooltips. This article shows how to do this with a combination of undocumented Matlab and Java hacks....
  4. Uitable sorting Matlab's uitables can be sortable using simple undocumented features...
]]>
A recent CSSM thread about implementing a system-wide GUI help system got me working on a post to present Matlab’s built-in hidden/unsupported mechanism for context-sensitive help. There are many different ways in which such a system can be implemented (read that thread for some ideas), so Matlab users are by no means limited to Matlab’s built-in implementation. However, the built-in system certainly merits consideration for its simplicity and usefulness.

We start with Matlab’s cshelp function (%matlabroot%\toolbox\matlab\uitools\cshelp.m). cshelp is semi-documented, meaning that it has a help section but no doc, online help or official support. This useful function was grandfathered (made obsolete) in Matlab 7.4 (R2007a) for an unknown reason and to my knowledge without any replacement. cshelp is entirely based on m-code (no hidden internal or Java code) and is surprisingly compact and readable.

cshelp basically attaches two new properties (CSHelpMode and CSHelpData) to the specified figure (this is done using the schema.prop mechanism which will be described in a separate post), temporarily disables all active uicontrols, modifies the figure’s WindowButtonDownFcn callback and sets the mouse cursor (using setptr – another semi-documented function) to an arrow with a question mark.

Clicking any object in the figure’s main area (beneath the toolbar), causes the modified WindowButtonDownFcn callback to run whatever is stored in the figure’s HelpFcn property (string, @function_handle or {@function_handle, params, …} format). Here is a simple example taken from CSSM (thanks Jérôme):

Hfcn = 'str=get(gco,''type''); title([''Type :'' str])';
set(gcf,'HelpFcn',Hfcn);
th = 0:0.314:2*pi;
plot(th,sin(th),'r-','linewidth',4);
uicontrol('units','normalized', 'position',[.45 .02 .1 .05]);
cshelp(gcf);
set(gcf,'CSHelpMode','on');

Simple context-sensitive help system

Simple context-sensitive help system

In order to exit CSHelp mode, the figure’s CSHelpMode property must be set to ‘off’. However, remember that all the figure’s uicontrols are disabled in CSHelp mode. Therefore, the user may use one or more of the following methods (other tactics are also possible, but the ones below seem intuitive):

  • Set the figure’s KeyPressFcn callback property to catch events (e.g., <ESC> key presses) and reset the CSHelpMode property from within the callback
  • Reset the CSHelpMode property at the end of the HelpFcn callback
  • Add a CS Help entry/exit option to the figure’s Help main menu
  • Add a CS Help entry/exit button to the figure toolbar

The following code sample implements all of these suggested tactics (the code to synchronize the states of the menu item and toolbar button is not presented):

% Set the <ESC> key press to exit CSHelp mode
keyFcn = ['if strcmp(get(gcbf,''CurrentKey''),''escape''), ' ...
             'set(gcbf,''CSHelpMode'',''off''); ' ...
          'end'];
set(gcf,'keyPressFcn',keyFcn);
 
% Exit CSHelp mode at the end of the CSHelp callback
helpFcn = 'title([''Type :'' get(gco,''type'')]); set(gcbf,''CSHelpMode'',''off'');';
set(gcf,'HelpFcn',helpFcn);
 
% Add a CSHelp button to the figure toolbar
% Note: retrieve the button icon from the CSHelp cursor icon
hToolbar = findall(allchild(gcf),'flat','type','uitoolbar');
oldPtr = getptr(gcf);
ptrData = setptr('help');
set(gcf, oldPtr{:});
icon(:,:,1) = ptrData{4}/2;  % Convert into RGB TrueColor icon
icon(:,:,2) = ptrData{4}/2;
icon(:,:,3) = ptrData{4}/2;
cbFcn = 'set(gcbf,''CSHelpMode'',get(gcbo,''state''))';
csName = 'Context-sensitive help';
uitoggletool(hToolbar,'CData',icon, 'ClickedCallback',cbFcn, 'TooltipString',csName);
 
% Add a CSHelp menu option to the Help main menu
% Note: unlike other main menus, the Help menu tag is empty, so
% ^^^^  findall(gcf,'tag','figMenuHelp') is empty... Therefore,
%       we find this menu by accessing the Help/About menu item
helpAbout = findall(gcf,'tag','figMenuHelpAbout');
helpMenu = get(helpAbout,'parent');
cbFcn = ['if strcmp(get(gcbo,''Checked''),''on''), ' ...
             'set(gcbo,''Checked'',''off''); ' ...
         'else, ' ...
             'set(gcbo,''Checked'',''on''); ' ...
         'end; ' ...
         'set(gcbf,''CSHelpMode'',get(gcbo,''checked''))'];
uimenu(helpMenu,'Label',csName,'Callback',cbFcn,'Separator','on');

Figure with context-sensitive help action in the main toolbar & menu

Figure with context-sensitive help action in the main toolbar & menu

cshelp has an additional optional argument, accepting another figure handle. This handle, if specified and valid, indicates a parent figure whose CSHelpMode, HelpFcn and HelpTopicMap properties should be shared with this figure (this is done using the handle.listener mechanism which will be described in a separate post). This option is useful when creating a multi-window GUI-wide context-sensitive help system. The user may then activate context-sensitive help in figure A and select the requested context object in figure B.

cshelp would normally be coupled with Matlab’s help system for non-trivial GUI implementations. The undocumented and hidden properties HelpTopicKey (of all handles) and HelpTopicMap (of figures), enable easy tie-in to the CSHelp system. A simplified sample is presented below:

Hfcn=['helpview(get(gco,''HelpTopicKey''),''CSHelpWindow'');'...
      'set(gcbf,''CSHelpMode'',''off'');' ];
set(gcf,'HelpFcn',Hfcn);
th = 0:0.314:2*pi;
hLine = plot(th,sin(th),'r-','linewidth',4);
set(hLine,'HelpTopicKey','MyCSHelpFile.html#Line');
set(gca,  'HelpTopicKey','MyCSHelpFile.html#Axes');

cshelp is by no way limited to presenting Matlab documentation: Refer to helpview‘s help section for an in-depth description of help maps and help topics. In a nutshell, helpview accepts any HTML webpage filepath (or webpage internal (#) reference), followed by optional parameter ‘CSHelpWindow’ (that indicates that the specified help page should be displayed in a stand-alone popup window rather than in the desktop’s standard Help tab), and optional extra parameters specifying the popup window’s figure handle and position. The webpage filepath parameter may be replaced by two string parameters, HelpTopicMap filepath and HelpTopicKey. Note that helpview itself is another semi-documented function.

]]>
https://undocumentedmatlab.com/blog_old/context-sensitive-help/feed 10
Setting status-bar texthttps://undocumentedmatlab.com/blog_old/setting-status-bar-text https://undocumentedmatlab.com/blog_old/setting-status-bar-text#comments Thu, 23 Jul 2009 22:01:40 +0000 https://undocumentedmatlab.com/?p=465 Related posts:
  1. Setting status-bar components Matlab status-bars are Java containers in which we can add GUI controls such as progress-bars, not just simple text labels...
  2. Detecting window focus events Matlab does not have any documented method to detect window focus events (gain/loss). This article describes an undocumented way to detect such events....
  3. Transparent Matlab figure window Matlab figure windows can be made fully or partially transparent/translucent or blurred - this article explains how...
  4. Figure toolbar components Matlab's toolbars can be customized using a combination of undocumented Matlab and Java hacks. This article describes how to access existing toolbar icons and how to add non-button toolbar components....
]]>
Most GUI windows nowadays, ranging from web browsers to editors and data-entry windows, have a small status-bar at their bottom. Statusbars are a great way to convey non-critical information to the user, in a non-intrusive manner (without popup windows).

Matlab windows are no exception: they too have status bars which are sometimes used by internal Matlab functions. Unfortunately, there is no documented way to modify Matlab statusbars. In this post I will demonstrate the undocumented way of setting status-bar text, which is probably the most useful use-case. In next week’s post, I will expand this to include more complex customizations, such as dynamic progress-bars or a corner grip.

Note: Users interested in non-intrusive status-bar messages, may also be interested in another non-intrusive messaging mechanism which I have described some months ago: Setting system tray popup messages.

Desktop window status-bar

We start with the simplest case of setting the desktop’s statusbar text. We have no further to go than the bottom of Matlab’s own uiopen (see %matlabroot%/toolbox/matlab/uitools/uiopen.m):

dt = javaMethod('getInstance', 'com.mathworks.mde.desk.MLDesktop');
if dt.hasMainFrame
    dt.setStatusText(message);
else
    disp(message);
end

Basically, we try to get the Java reference to the Matlab desktop, see if it has an open window frame and if so then we use its setStatusText() method to display a text message; if not then we display the message in the Command Window (which is probably a non-window console).

Unfortunately, if we place this code in our m-files as-is, our status message will be overridden by Matlab’s “busy” message. A solution for this is to use a one-time (discardable) timer. Another complication is meant for supporting Matlab 6, in which we get the desktop reference differently, and which did not yet have the timer function. The final code now looks like this:

%% Set the status bar text of the Matlab desktop
function setDesktopStatus(statusText)
  % First, get the desktop reference
  try
    desktop = com.mathworks.mde.desk.MLDesktop.getInstance;     % Matlab 7+
  catch
    desktop = com.mathworks.ide.desktop.MLDesktop.getMLDesktop; % Matlab 6
  end
 
  if desktop.hasMainFrame
    % Schedule a timer to update the status text
    % Note: can't update immediately (will be overridden by Matlab's 'busy' message)
    try
      timerFcn = {@setText,desktop,statusText};
      t = timer('TimerFcn',timerFcn, 'StartDelay',0.05, 'ExecutionMode','singleShot');
      start(t);
    catch
      % Probably an old Matlab version that still doesn't have timer
      desktop.setStatusText(statusText);
    end
  else
    disp(statusText);
  end
 
%% Utility function used as setDesktopStatus's internal timer's callback
function setText(varargin)
  if nargin == 4  % just in case...
    targetObj  = varargin{3};
    statusText = varargin{4};
    targetObj.setStatusText(statusText);
  else
    % should never happen...
  end

Figure window status-bar

Setting the status-bar text on figure windows is slightly more difficult: getstatus and setstatus appear to be early attempts by Matlab to enable users an access to a figure’s statusbar. In this early attempt, Matlab assumes that the user prepares a text label having a tag of ‘status’. getstatus then returns this label’s string, while setstatus modifies it:

uicontrol('Parent',gcf,'Style','text','Tag','Status');
setstatus(gcf, 'Goodbye');
string = getstatus(gcf);

Unfortunately, nothing prevents the user from placing the label anywhere in the figure, and also from having multiple such labels at once, adding to the confusion. The result is inconsistent with normal windowing practices, and this is probably the reason that MathWorks have grandfathered these functions in Matlab 7.4 (R2007a). It would be much more logical for Matlab to have the statusbar accessible via a figure property, and perhaps this will happen in some future version.

A better, consistent and more flexible access to the figure statusbar can be achieved by using some undocumented Java functions. In a nutshell, we get the figure’s JavaFrame property (which Matlab has warned might be discontinued in some near upcoming release), which is sort of a handle reference to the Java window underlying the Matlab figure window (not exactly but close enough for today). We then travel up and down the JavaFrame window objects hierarchy (use my FindJObj utility on the File Exchange to understand this hierarchy) until we get to the status bar object. We then set its text and make it visible (it’s invisible by default). Here is a trimmed-down version (excluding the necessary sanity checks, exception handling etc.):

% Alternative #1 (hFig = requested figure's handle)
jFrame = get(hFig,'JavaFrame');
jFigPanel = get(jFrame,'FigurePanelContainer');
jRootPane = jFigPanel.getComponent(0).getRootPane;
jRootPane = jRootPane.getTopLevelAncestor;
statusbarObj = jRootPane.getStatusBar;
statusbarObj.setText(statusText);
jRootPane.setStatusBarVisible(1);
 
% Alternative #2
jFrame = get(hFig,'JavaFrame');
jRootPane = jFrame.fFigureClient.getWindow;
statusbarObj = com.mathworks.mwswing.MJStatusBar;
jRootPane.setStatusBar(statusbarObj);
statusbarObj.setText(statusText);


simple figure status-bar text message

simple figure status-bar text message


StatusBar utility

I’ve created a wrapper function, aptly called statusbar, encapsulating all the above with some additional error checking etc. I have posted statusbar on the MathWorks File Exchange. Readers are encouraged to look at this submission’s source code for examples of statusbar manipulation. Here are several usage examples:


statusbar usage examples (click to see details)

statusbar usage examples (click to see details)


]]>
https://undocumentedmatlab.com/blog_old/setting-status-bar-text/feed 32