Quantcast
Channel: Undocumented Matlab
Viewing all articles
Browse latest Browse all 219

treeTable

$
0
0

Since Matlab 7.0 (R14), Matlab has included a built-in GUI table control (uitable), at first as a semi-documented function and in release 7.6 (R2008a) as a fully-documented function. Useful as this control is, it lacks many features that are expected in modern GUIs, including sorting, filtering, cell-specific appearance and behavior, gridline customization etc. In past articles I have explained how uitable can be customized to achieve a more professional-looking table. I expanded on this in my book and my detailed uitable customization report.

Today I explain how a grouping hierarchy can be achieved in a table control that can be used in Matlab GUI. Such a control, which is a combination of a uitree and uitable, is typically called a tree-table. We can find numerous examples of it in everyday usage. I have encapsulated the functionality in a utility called treeTable on the Matlab File Exchange (#42946). The utility is provided with full source code and open-source license, and readers are welcome to use and modify it. A detailed explanation of the technicalities follows below, but if you’re just interested in having a sortable, rearrangeable, customizable, groupable table control, then all you need to do is download and use the utility.

treeTable utility

treeTable utility

headers = {'ID','Label','Logical1','Logical2','Selector','Numeric'};
data = {1,'M11',true, false,'One', 1011;  ...
        1,'M12',true, true, 'Two', 12;   ...
        1,'M13',false,false,'Many',13.4; ...
        2,'M21',true, false,'One', 21;  ...
        2,'M22',true, true, 'Two', 22;   ...
        3,'M31',true, true, 'Many',31;   ...
        3,'M32',false,true, 'One', -32;  ...
        3,'M33',false,false,'Two', 33; ...
        3,'M34',true, true, 'Many',34;  ...
};
selector = {'One','Two','Many'};
colTypes = {'label','label','char','logical',selector,'double'};
colEditable = {true, true, true, true, true}
icons = {fullfile(matlabroot,'/toolbox/matlab/icons/greenarrowicon.gif'), ...
         fullfile(matlabroot,'/toolbox/matlab/icons/file_open.png'), ...
         fullfile(matlabroot,'/toolbox/matlab/icons/foldericon.gif'), ...
}
 
% Create the table in the current figure
jtable = treeTable('Container',gcf, 'Headers',headers, 'Data',data, ...
                   'ColumnTypes',colTypes, 'ColumnEditable',colEditable, 'IconFilenames',icons);
 
% Collapse Row #6, sort descending column #5 (both are 0-based)
jtable.expandRow(5,false);  % 5=row #6; false=collapse
jtable.sortColumn(4,true,false);  % 4=column #5; true=primary; false=descending

The basic implementation concept

Unfortunately, uitable as-is cannot be customized to have groupable rows. It derives from JIDE’s SortableTable, rather than one of its groupable derived classes. On the other hand, uitree (don’t you agree that after a decade of this so-useful function being semi-documented it ought to be made official?) uses a different class hierarchy outside com.jidesoft.grid, and so it cannot be easily customized to display rows (as opposed to simple labels).

These limitations mean that we cannot use uitable or uitree and need to use a custom component. Luckily, such a component is available in all Matlab installations, on all platforms. It is part of the grid components package, on which Matlab GUI has relied for many years, by JIDE Software. JIDE Grids is a collection of components that extend the standard Java Swing JTable component, and is included in each Matlab installation (/java/jarext/jide/jide-grids.jar under the Matlab root). I discussed multiple JIDE controls in this blog over the years. You can find further details on JIDE Grids in the Developer Guide and the Javadoc documentation.

In fact, there are no less than three different components that we could use in our case: TreeTable, GroupTable and HierarchicalTable:

JIDE Grids class hierarchy (we normally use only one of the marked classes)

JIDE Grids class hierarchy (we normally use only one of the marked classes)

Note that we cannot use PropertyTable since that component is limited to only two columns. This is perfect for presenting property names and values, which is the reason it is used by Matlab’s inspect function and my generic propertiesGUI utility or Levente Hunyadi’s Property Grid utility. But in this case we wish to display a general multi-column table, so PropertyTable is a no-go.

TreeTable and GroupTable enable data rows that have similar type (class), whereas HierarchicalTable enables more flexibility, by allowing display of any component type (including full tables) in child rows. This flexibility comes with a price that customizing a HierarchicalTable is more difficult than TreeTable or GroupTable. These latter two components are quite similar; we use GroupTable, which extends TreeTable with the ability to automatically group rows that have the same value in a certain column.

Data model

The above-mentioned table classes all derive from SortableTable (which also underlies uitable). Unfortunately, something in the Matlab-Java interface breaks the ability of the JIDE table classes (or rather, their data model) to understand numeric values for what they are. As a result, sorting columns is done lexically, i.e. “123″ < “34″ < “9″. To fix this, I’ve included a custom Java table model (MultiClassTableModel) with the treeTable utility, which automatically infers the column type (class) based on the value in the top row (by overriding the getColumnClass() method).

Using this new class is pretty easy:

% Create the basic data-type-aware model using our data and headers
javaaddpath(fileparts(mfilename('fullpath')));  % add the Java class file to the dynamic java class-path
model = MultiClassTableModel(data, headers);  % data=2D cell or numeric array; headers=cell array of strings
 
% Wrap the standard model in a JIDE GroupTableModel
com.mathworks.mwswing.MJUtilities.initJIDE;  % initialize JIDE
model = com.jidesoft.grid.DefaultGroupTableModel(model);
model.addGroupColumn(0);  % make the first column the grouping column
model.groupAndRefresh;  % update the model data
 
% Use the generated model as the data-model of a JIDE GroupTable
jtable = eval('com.jidesoft.grid.GroupTable(model);');  % prevent JIDE alert by run-time (not load-time) evaluation
jtable = handle(javaObjectEDT(jtable), 'CallbackProperties');  % ensure that we're using EDT
 
% Enable multi-column sorting
jtable.setSortable(true);
 
% Present the tree-table within a scrollable viewport on-screen
scroll = javaObjectEDT(JScrollPane(jtable));
[jhscroll,hContainer] = javacomponent(scroll, tablePosition, hParent);
set(hContainer,'units', 'normalized','pos',[0,0,1,1]);  % this will resize the table whenever its container is resized

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

javacomponent is the undocumented built-in Matlab function that adds Java Swing components to a Matlab figure, using the given dimensions and parent handle. I discussed it here.

Callbacks

There are two main callbacks that can be used with treeTable:

  • table data update – this can be set by uncommenting line #237 of treeTable.m:
    set(handle(jtable.getOriginalModel,'CallbackProperties'), 'TableChangedCallback', {@tableChangedCallback, jtable});

    which then activated the sample tableChangedCallback() function (lines #684-694). Naturally, you can also set your own custom callback function.

    % Sample table-editing callback
    function tableChangedCallback(hModel,hEvent,jtable)
        % Get the modification data
        modifiedRow = get(hEvent,'FirstRow');
        modifiedCol = get(hEvent,'Column');
        label   = hModel.getValueAt(modifiedRow,1);
        newData = hModel.getValueAt(modifiedRow,modifiedCol);
     
        % Now do something useful with this info
        fprintf('Modified cell %d,%d (%s) to: %s\n', modifiedRow+1, modifiedCol+1, char(label), num2str(newData));
    end  % tableChangedCallback
  • row selection update – this is currently enabled in line #238 of treeTable.m:
    set(handle(jtable.getSelectionModel,'CallbackProperties'), 'ValueChangedCallback', {@selectionCallback, jtable});

    which then activated the sample selectionCallback() function (lines #696-705). Naturally, you can also set your own custom callback function.

    % Sample table-selection callback
    function selectionCallback(hSelectionModel,hEvent,jtable)
        % Get the selection data
        MinSelectionIndex  = get(hSelectionModel,'MinSelectionIndex');
        MaxSelectionIndex  = get(hSelectionModel,'MaxSelectionIndex');
        LeadSelectionIndex = get(hSelectionModel,'LeadSelectionIndex');
     
        % Now do something useful with this info
        fprintf('Selected rows #%d-%d\n', MinSelectionIndex+1, MaxSelectionIndex+1);
    end  % selectionCallback

Some useful features of treeTable

  • Sortable columns (including numeric columns)
  • Rearrangeable columns (drag headers left/right)
  • Auto-fit the table columns into the specified container width
  • Manually resize columns by dragging the column divider gridlines (not just the header dividers as in uitable)
  • Flat or groupable table, based on the specified Groupable parameter (default=true)
  • Selector cells only show the drop-down arrow of the currently-selected cell (unlike uitable which shows it for all the column cells)
  • Selector cells enable editing, unlike uitable that only enables selecting among pre-defined values
  • Ability to attach user-defined icons for the leaf rows and the grouping rows (expanded/collapsed)
  • Easily attach custom cell editors or renderers to any table column (see my book and my detailed uitable customization report for details)

All of these features can be turned on/off using the control’s properties. Again, see my book or report for details (or ask me to do it for you…).

 
Related posts:
  1. Uitable sorting Matlab's uitables can be sortable using simple undocumented features...
  2. Uitable customization report 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...
  3. Uitable cell colors A few Java-based customizations can transform a plain-looking data table into a lively colored one. ...
  4. JIDE Property Grids The JIDE components pre-bundled in Matlab enable creating user-customized property grid tables...
 

Viewing all articles
Browse latest Browse all 219

Trending Articles