After several years in which I have mentioned my uiinspect utility in posts, I figured it is high time to actually describe this utility in detail.
uiinspect, downloadable from the Matlab file Exchange, is a Matlab GUI utility that inspects the specified object and provides detailed information about its super-classes, methods, properties, static fields and callbacks in a unified Matlab window. uiinspect works on a very wide variety of inputs: Matlab/Java/Dot-Net class names and class objects; COM/DCOM objects, Handle Graphics handles etc.
In essence, uiinspect incorporates the information presented by the following built-in Matlab functions: inspect, get, and methodsview. uiinspect also presents additional aspects that are not available in any built-in Matlab function (for example, inheritance information, undocumented hidden properties, properties meta-data, grouping of callbacks by type).
uiinspect displays hidden properties and fields that are not normally displayed in Matlab (see my related getundoc utility). Property meta-data such as type, accessibility, visibility and default value are also displayed. Object properties and callbacks may be modified interactively within the uiinspect window.
Of over 40 utilities that I have so-far submitted to the File Exchange, uiinspect is one of my most complex (together with findjobj). It has undergone 24 revisions since its initial release in 2007. The latest revision has nearly 3000 source-code lines, of which 75% are code lines, 20% are comment lines and the rest are empty spacer lines. That’s a pretty complex utility to describe, and it relies on plenty of undocumented aspects, so today’s post will only highlight the important aspects. Readers are more than welcome to have a look at the source code for additional details. It is pretty-well documented, if I may say so myself.
The basic syntax is:
hFig = uiinspect(handle)
hFig = uiinspect(0); % the root handle hFig = uiinspect(handle(0)); hFig = uiinspect(gcf); % current figure hFig = uiinspect(handle(gcf)); uiinspect('java.lang.String'); % Java classname uiinspect(java.lang.String('yes')); % Java object uiinspect(get(gcf,'JavaFrame')); % Java object uiinspect(classhandle(handle(gcf))); % UDD class object uiinspect(findprop(handle(gcf),'MenuBar')); % UDD property uiinspect(actxserver('Excel.Application')); % COM object uiinspect(Employee) % Matlab class object uiinspect(?handle) % Matlab metaclass object uiinspect('meta.class') % Matlab class name uiinspect(System.DateTime.Now) % Dot-Net object
uiinspect returns a handle to the created figure window. uiinspect opens a regular Matlab figure window which may be accessed via hFig (unlike Matlab’s methodsview and inspect functions which open Java frame that is not accessible from Matlab).
Unlike Matlab’s functions, multiple uiinspect windows can be opened simultaneously, for different objects. The differentiation is done based on figure title, which contains the inspected object’s name (if available) and its class – reinspecting the same object will reuse the existing figure window, but in all other cases a new figure window will be created.
uiinspect includes the following information panels, that shall be described separately below:
- Class information (including superclasses, if applicable)
- Methods (for objects) or graphic handle hierarchy (for Handle Graphics)
- Callbacks (where applicable)
- Inspectable properties
- Other properties plus full meta-data (where applicable)
The panels are fully resizable. We can drag the divider lines up/down or left/right and the contents automatically adjust accordingly. Each panel has a minimal viewable width/height, and the dividers cannot be dragged to squeeze the panels below these minimums – they can only be minimized, which hides the relevant panel entirely. To minimize a panel, simply click the relevant small arrow mark on the divider. The opposite arrow mark next to it maximizes the panel, effectively minimizing the panel on the other side. Once minimized/maximized, the divider can be restored by simply clicking it once, or by dragging it (again, panel minimum sizes apply).
uiinspect only uses Java panels, so implementing the dividers required use of the simple JSplitPane. In a general case where we might wish to embed Matlab graphs in one of the side panels, we would need to employ a more sophisticated solution (see my UISplitPane utility).
The top-left panel displays a label with information about the object’s class and super-classes inheritance (where applicable).
The class name itself is hyper-linked to the class’s documentation: if this is a standard Java class, then to the official online javadoc for this class which opens up in Matlab’s internal web browser. In fact, since different Matlab releases use different JVM versions (1.3 through 1.6), the link points to the documentation page corresponding to the JVM version actually used.
If the class is non-Java, the hyperlink displays the class’s help section in Matlab’s Command Window / console. The panel’s tooltip displays the same information in a slightly different manner.
The hyperlink in the label is actually an optical illusion. In fact, the entire label is hyper-linked, and clicking any part of it will display the relevant documentation (a similar optical illusion is used to display the hyperlink at the footer of the utility window). The illusion is achieved using Matlab’s HTML formatting, where the part of the label string consisting of the class name is underlined. The cursor was dynamically modified to a pointed hand-finger when the mouse hovers over the label, using the following simple Java-based command:
Special treatment is done to extract the class’s superclass, the interfaces that it implements and any possible class qualifiers (for example, “final”).
For those interested to dig within the code, all this is done in uiinspect‘s getMethodsPane function.
Next to the class label, a checkbox is presented (“Extra”). Clicking this checkbox displays additional meta-data information (qualifiers, interrupts and inheritance) in the methods pane beneath. Not all classes have all these extra meta-data fields – only the relevant extra meta-information fields are displayed. If there are is extra meta-data, then the checkbox is not displayed. This is done in the getMethodsTable function.
Methods or HG hierarchy panel
The utility’s main panel displays either a table of methods (functions) for a class object, or a tree hierarchy for an HG handle.
Class object methods
The methods table takes the information from the getObjMethods function, which is an adaptation of Matlab’s built-in methodsview function. Part of the adaptation is to hyperlink all class references (used in the methods’ inputs, outputs and meta-data), such that clicking them will open new corresponding uiinspect windows.
The methods data is displayed within a non-editable Java table (in the getMethodsTable function) that auto-resizes the columns. The table columns are sortable, even sortable on multiple columns by CTRL-clicking (methodsview allows only simple sorting). This is done using JIDE’s TreeTable component. The table is placed within a scroll-pane having automatic scrollbars that only appear as needed.
The table’s MouseMovedCallback property is set to tbMouseMoved, which updates the mouse cursor (either regular or pointed finger) based on the current mouse position in the table (whether over a hyperlinked cell or not).
The table’s MousePressedCallback property is set to tbMousePressed, which opens new uiinspect figure windows for the hyperlinked classes (if any) in the clicked cell.
HG hierarchy tree
For HG handles, getHandleTree creates a Java tree that displays the hierarchy of HG children (as recursively reported by any HG handle’s Children property). For convenience, I have chosen to use the built-in component
com.mathworks.hg.peer.UITreePeer that underlies the built-in uitree function. For performance reasons, the tree is not fully evaluated: the inspected handle’s Parent is set as the tree’s Root. The root node is expanded to get all the parent’s Children (i.e., the inspected handle’s siblings), and then the inspected handle’s tree node is again expanded to display its direct descendents.
A MouseMovedCallback is set on the tree to process mouse hover events in the treeMouseMovedCallback function. This function updates the tree tooltip dynamically, in the sense that it presents a different tooltip for different handles (tree nodes).
Invalid HG handles (this can happen if the HG handle was deleted since the time that uiinspect generated the tree) are displayed with a special warning message.
This dynamic tree behavior is achieved by storing the relevant handle information in the UserData of the different tree nodes. Unfortunately, starting in R2012a, Matlab has made a change in the internal support of Java objects, and the UserData property is no longer available. Such a case is detected and the data is stored in the tree nodes’ ApplicationData property instead (using setappdata(node,’userdata’,…) ).
A MousePressedCallback is set on the tree to process context (right-click) events in the treeMousePressedCallback function. The context-menu is also dynamic, in the sense that it presents a different context menu for different handles (tree nodes), again based on their user-data.
Left-clicking a node is not processed by treeMousePressedCallback, but rather by the tree’s NodeSelectedCallback which is processed in nodeSelected, and by NodeExpandedCallback which is processed by nodeExpanded. nodeSelected reloads uiinspect for the selected handle; nodeExpanded merely displays the expanded handle’s children.
Since the ‘+’ sign (which triggers nodeExpanded) and the handle icon (which triggers nodeSelected) are so close, we should be careful to click the ‘+’, otherwise the entire uiinspect window will reload the tree based on the clicked node… If anyone has a good idea how to solve this dilemma, then I’m all ears.
Like the methods table, the tree is also placed in a dynamic scroll-pane that displays scrollbars only as needed.
The callbacks panel, computed in getCbsData is based on a reflection of the object’s data as reported by the undocumented built-in classhandle function. I aggregate all the object’s events, as well as all the object property names that end with ‘Fcn’ or ‘Callback’. This takes care (I hope) of all the different manners by which different kinds of objects raise events that are trappable in Matlab callbacks. Specifically, it takes care of Java/Matlab classes as well as HG handles and COM objects. If anyone thinks that I have forgotten something, please let me know.
The getCbsPane function then displays the callbacks data (callbacks’ property name and value) in a Java table (JIDE PropertyTable, JIDE TreeTable, or failing those a simple JTable).
The callbacks are automatically grouped by name into logical groups (in getTreeData). For example, all callbacks whose names start with “Mouse*” are grouped in the “Mouse callbacks” group. The last group is always called “Other callbacks” and contains all callbacks for which a matching sibling callback has not been found. The groups are automatically collapsed by default; if only a single group is found then this group is automatically opened (for example, in the case of uiinspect(0) ).
The callbacks table’s toolbar enables displaying the callbacks by groups or sorted alphabetically. It also has “expand” and “collapse” icons that affect all the groups.
A checkbox next to the table’s toolbar enables hiding standard Java Swing callbacks. This is important when we inspect Java controls and only wish to see its unique callbacks. When using this checkbox, red Java exceptions are sometimes displayed in the Matlab console – these are harmless and you can safely ignore them (I hope to find a way to prevent them one day).
The table’s right column displays the callback properties values (if available). This column is editable and we can interactively modify any callback’s property. As shown, we can enter callback value in either of Matlab’s supported formats: string, function handle and (for non-COM objects only!) a cell array of function handle and additional data. An error message will be displayed if the callback value is invalid or cannot be set for some reason.
If it is determined that there are no callbacks, then the callbacks panel is automatically minimized, to enable maximum space for the methods panel above it.
Properties inspector panel
The properties inspection panel, prepared in getPropsPane, is actually composed of two separate panes: the top pane uses the built-in Matlab component
com.mathworks.mlwidgets.inspector.PropertyView, which in turn uses JIDE’s PropertyTable.
PropertyView is the same component used by Matlab’s standard inspect function (that’s how I came to know it, if anyone wonders).
The benefit of using Matlab’s
PropertyView component rather than JIDE’s
PropertyTable is that
PropertyView has the very useful method setObject which I use to point the component at the inspected object, which automatically infers its non-hidden properties and updates the table, saving me a lot of work.
There are two drawbacks of using Matlab’s
PropertyViewonly displays non-hidden properties. One day when I have time, I intent to add the hidden properties to the resulting JIDE
PropertyTable. But for now it only shows non-hidden properties.
PropertyViewcauses a Matlab crash on some Matlab releases, in case dbstop if error is active (this can be replicated using Matlab’s standard inspect). I therefore regrettably need to disable this specific dbstop.
I’ve been meaning to do these two fixes ever since I released uiinspect back in 2007, but for now that’s the way it is…
The properties data is retrieved via the getPropsData function. This function uses the built-in Matlab functions meta.class.fromName(className) and metaclass(classObject) to get the class handle of Matlab classes (in getMetaClass); similarly, loadClass loads the class definition for a Java class. I inspect these class handles for their contained properties. I then use the fieldnames function to add static class fields, which are not standard properties (for example, “RED” is a static field of the
From the class handle, I retrieve the full definition of each property. This includes meta-data such as whether the property is regular or hidden (undocumented); settable or not; gettable or not; and any additional qualifiers (e.g., Sealed, Dependent, Constant, Abstract, Transient, Default (factory) value).
We now have a list of all properties and static fields, and this is used to display the entire properties data in the properties panel’s title (“Inspectable object properties”) tooltip. This tooltip, created in updateObjTooltip and getPropsHtml, uses some fancy HTML formatting to display all the object’s properties and values, color- and font-style-coded to show which of the properties is read-only, hidden, undefined etc.
The entire information is also displayed in the properties meta-data pane (“Other properties”) beneath JIDE’s inspector pane. Here we use a simple Java table to display the information in color-coding (gray for read-only properties; blue for static fields; red for irretrievable properties).
Separate checkboxes enable displaying all properties (by default only the properties that are NOT displayed in JIDE’s inspector table are displayed); and whether or not to display the extra meta-data in the properties table (by default only the property name and current value are displayed).
In some cases (e.g., Dot-Net objects), Matlab’s inspector does not know how to extract the property-bean information and so the
PropertyView inspector is not shown, only the “other properties” table.
Both JIDE’s inspector table and the “other properties” table enable the user to modify existing values. Note that in some cases Matlab prevents interactive update of some properties, and in some other cases I have seen Matlab hang when trying to update a few specific properties. But in most cases updating the value does work as expected.
The combination of the inspector table, the meta-data table and the tooltip, enable users to fully understand the accessible properties of the inspected object. Of course, it would have been much better to merge the JIDE inspector table with the hidden properties (=additional rows) and meta-data (=additional columns). But let’s leave something for the future, shall we?
uiinspect employs the same auto-update background mechanism used by findjobj – after presenting the GUI, the utility silently checks the File Exchange webpage to see whether any newer version of this utility has been uploaded. If so, then a popup notice is presented with the date and description of the latest version. The popup enables users to download the newer version into their Matlab path, or skip. There is also an option to skip the update and not to remind ever again.
I find this background auto-update mechanism quite useful and generic. In fact, I uploaded it as a separate File Exchange utility today, following Brett Shoelson’s suggestion last month. You can find the underlying code in the checkVersion function.
- cleanup internal functions, remove duplicates etc.
- link property objects to another uiinspect window for these objects
- display object children (& link to them) – COM/Java
- find a way to merge the other-properties table with the inspector table (hidden props + meta-data)
- find a way to use the inspector without disabling dbstop if error
- Fix: some fields generate a Java Exception from:
- Fix: using the “Hide standard callbacks” checkbox sometimes issues Java Exceptions on the console
- Fix: In HG tree view, sometimes the currently-inspected handle is not automatically selected
I would be happy if anyone can help with any of these.
I believe that this has been my longest blog post ever; certainly the one that I have labored most over. This correlates well with the uiinspect utility, which has been one of my most complex tasks. I’m guessing I must have invested 100-200 man-hours developing and improving it over the years.
I hope you find uiinspect as useful and as fun as I do. I believe that its source-code is certainly worth reading if you are interested in any advanced Matlab GUI programming, showing how Java GUI components can be combined in Matlab. Go ahead and download uiinspect from the Matlab file Exchange.