I would like to welcome guest blogger Levente Hunyadi.
Matlab’s property inspector
We often wish to edit properties of heterogeneous objects using a common interface. Matlab’s property inspector, invoked with the built-in inspect function, answers this need. The inspector is based on a two-column table of property names and values. Properties and their values are populated automatically, and the user can edit values in-place. The inspector enables property categorization, sub-categorization and sorting, which help users find and modify properties easily. For each property, the inspector displays a matching edit control: editbox/combobox/checkbox etc. This simplifies property value editing and prevents illegal value entry. Matlab’s GUI builder, GUIDE, uses the inspector to let users edit GUI properties such as position, color etc. It is also used by other tools such as the Plot Editor.
Unfortunately, Matlab’s property inspector is limited to Handle Graphics, Java and COM objects, and cannot be used for structures or user-defined Matlab classes. We shall see below how to set up our own property grid, populate it with data, and subscribe to property change events. This is a rather procedural approach. It is usually more convenient to use a declarative approach in which a structure or Matlab class is passed to a function that automatically discovers its properties and their meta-information. The Property Grid utility at Matlab File Exchange provides these services.
A simple property grid
Matlab’s property inspector is based on a property grid control by JIDE Software. JIDE Grids is a collection of components that extend the standard Java Swing JTable component, and is included in each Matlab installation (/java/jarext/jide/jide-grids.jar under the Matlab root). In particular, JIDE Grids includes the PropertyTable class, which is a fully customizable property grid component. You can find further details on JIDE Grids in the Developer Guide and the Javadoc documentation.
There are several related classes associated with the PropertyTable class. First, a PropertyTableModel encapsulates all properties that are visualized in the property grid. Each property derives from the Property abstract class, which features some common actions to properties, most notably to get and set property value. DefaultProperty is a default concrete subclass of Property. Finally, PropertyPane decorates a property grid with icons for changing category view to alphabetically sorted view as well as expanding and collapsing categories, and a description text box at the bottom that can be shown or hidden.
Here are the DefaultProperty fields and their respective roles:
|Name||Interal property name, not necessarily displayed, used as a key to identify the property.|
|DisplayName||A short property name shown in the left column of the property grid.|
|Description||A concise description of the property, shown at the bottom of the property pane, below the grid.|
|Type||The Java type associated with the property, used to invoke the appropriate renderer or editor.|
|EditorContext||An editor context object. If set, both the type and the context are used to look up the renderer or editor to use. This lets, for instance, one flag value to display as a true/false label, while another as a checkbox.|
|Category||A string specifying the property’s category, for grouping purposes.|
|Editable||Specifies whether the property value is modifiable or read-only.|
|Value||The current property value, as a Java object.|
Just as with any Java object, these fields may either be accessed with the Java get/set semantics (e.g. getName() or setName(name)), or the Matlab get/set semantics (e.g. get(prop,’Name’) or set(prop,’Name’,name)). When using the Matlab syntax, remember to wrap the Java object in a handle() call, to prevent a memory leak.
To use a property grid in Matlab, first construct a set of DefaultProperty objects. For each object, set at least the name, type and initial value. Next, add the properties to a table model. Finally, construct a property grid with the given table model and encapsulate in a property pane:
% Initialize JIDE's usage within Matlab com.mathworks.mwswing.MJUtilities.initJIDE; % Prepare the properties list list = java.util.ArrayList(); prop1 = com.jidesoft.grid.DefaultProperty(); prop1.setName('stringProp'); prop1.setType(javaclass('char',1)); prop1.setValue('initial value'); prop1.setCategory('My Category'); prop1.setDisplayName('Editable string property'); prop1.setDescription('A concise description for my property.'); prop1.setEditable(true); list.add(prop1); prop2 = com.jidesoft.grid.DefaultProperty(); prop2.setName('flagProp'); prop2.setType(javaclass('logical')); prop2.setValue(true); prop2.setCategory('My Category'); prop2.setDisplayName('Read-only flag property'); prop2.setEditable(false); list.add(prop2); % Prepare a properties table containing the list model = com.jidesoft.grid.PropertyTableModel(list); model.expandAll(); grid = com.jidesoft.grid.PropertyTable(model); pane = com.jidesoft.grid.PropertyPane(grid); % Display the properties pane onscreen hFig = figure; panel = uipanel(hFig); javacomponent(pane, [0 0 200 200], panel); % Wait for figure window to close & display the prop value uiwait(hFig); disp(prop1.getValue());
Here, com.mathworks.mwswing.MJUtilities.initJIDE is called to initialize JIDE’s usage within Matlab. Without this call, we may see a JIDE warning message in some Matlab releases. We only need to initJIDE once per Matlab session, although there is no harm in repeated calls.
javaclass is a function (included in the Property Grid utility, or directly downloadable from here) that returns a Java class for the corresponding Matlab type with the given dimension: javaclass(‘logical’) or javaclass(‘logical’,0) (a single logical flag value) returns a java.lang.Boolean class; javaclass(‘char’,1) (a character array) returns a java.lang.String class; javaclass(‘double’,2) (a matrix of double-precision floating point values) returns double.
javacomponent is the undocumented built-in Matlab function that adds Java Swing components to a Matlab figure, using the given dimensions and parent handle. When the user closes the figure, prop.getValue() fetches and displays the new property value.
Next week’s article will show how to add more complex renderers and editors (display the flag value as a checkbox for example), define nested properties, and subscribe to property value change events. So stay tuned…