UI controls – 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 Matlab toolstrip – part 6 (complex controls)https://undocumentedmatlab.com/blog_old/matlab-toolstrip-part-6-complex-controls https://undocumentedmatlab.com/blog_old/matlab-toolstrip-part-6-complex-controls#comments Mon, 21 Jan 2019 16:00:38 +0000 https://undocumentedmatlab.com/?p=8235 Related posts:
  1. Matlab toolstrip – part 4 (control customization) Matlab toolstrip components (controls) can be customized in various ways, including user-defined callbacks. ...
  2. Matlab toolstrip – part 2 (ToolGroup App) Matlab users can create custom Apps with toolstrips and docked figures. ...
  3. Matlab toolstrip – part 3 (basic customization) Matlab toolstrips can be created and customized in a variety of ways. ...
  4. Matlab toolstrip – part 7 (selection controls) Matlab toolstrips can contain a wide variety of selection controls: popups, combo-boxes, and galleries. ...
]]>
In previous posts I showed how we can create custom Matlab app toolstrips using simple controls such as buttons and checkboxes. Today I will show how we can incorporate more complex controls into our toolstrip: button groups, edit-boxes, spinners, sliders etc.

Some custom Toolstrip Controls

Toolstrips can be a bit complex to develop so I’m proceeding slowly, with each post in the miniseries building on the previous posts. I encourage you to review the earlier posts in the Toolstrip miniseries before reading this post.

The first place to search for potential toostrip components/controls is in Matlab’s built-in toolstrip demos. The showcaseToolGroup demo displays a large selection of generic components grouped by function. These controls’ callbacks do little less than simply output a text message in the Matlab console. On the other hand, the showcaseMPCDesigner demo shows a working demo with controls that interact with some docked figures and their plot axes. The combination of these demos should provide plenty of ideas for your own toolstrip implementation. Their m-file source code is available in the %matlabroot%/toolbox/matlab/toolstrip/+matlab/+ui/+internal/+desktop/ folder. To see the available toolstrip controls in action and how they could be integrated, refer to the source-code of these two demos.

All toolstrip controls are defined by classes in the %matlabroot%/toolbox/matlab/toolstrip/+matlab/+ui/+internal/+toolstrip/ folder and use the matlab.ui.internal.toolstrip package prefix, for example:

% Alternative 1:
hButton = matlab.ui.internal.toolstrip.Button;
 
% Alternative 2:
import matlab.ui.internal.toolstrip.*
hButton = Button;

For the remainder of today’s post it is assumed that you are using one of these two alternatives whenever you access any of the toolstrip classes.

Top-level toolstrip controls

ControlDescriptionImportant propertiesCallbacksEvents
EmptyControlPlaceholder (filler) in container column(none)(none)(none)
LabelSimple text label (no action)Icon, Text (string)(none)(none)
ButtonPush-buttonIcon, Text (string)ButtonPushedFcnButtonPushed
ToggleButtonToggle (on/off) buttonIcon, Text (string), Value (logical true/false), ButtonGroup (a ButtonGroup object)ValueChangedFcnValueChanged
RadioButtonRadio-button (on/off)Text (string), Value (logical true/false), ButtonGroup (a ButtonGroup object)ValueChangedFcnValueChanged
CheckBoxCheck-box (on/off)Text (string), Value (logical true/false)ValueChangedFcnValueChanged
EditFieldSingle-line editboxValue (string)ValueChangedFcnValueChanged, FocusGained, FocusLost
TextAreaMulti-line editboxValue (string)ValueChangedFcnValueChanged, FocusGained, FocusLost
SpinnerA numerical spinner control of values between min,maxLimits ([min,max]), StepSize (integer), NumberFormat (‘integer’ or ‘double’), DecimalFormat (string), Value (numeric)ValueChangedFcnValueChanged, ValueChanging
SliderA horizontal slider of values between min,maxLimits ([min,max]), Labels (cell-array), Ticks (integer), UseSmallFont (logical true/false, R2018b onward), ShowButton (logical true/false, undocumented), Steps (integer, undocumented), Value (numeric)ValueChangedFcnValueChanged, ValueChanging
ListBoxList-box selector with multiple itemsItems (cell-array), SelectedIndex (integer), MultiSelect (logical true/false), Value (cell-array of strings)ValueChangedFcnValueChanged
DropDownSingle-selection drop-down (combo-box) selectorItems (cell-array), SelectedIndex (integer), Editable (logical true/false), Value (string)ValueChangedFcnValueChanged
DropDownButtonButton that has an associated drop-down selectorIcon, Text (string), Popup (a PopupList object)DynamicPopupFcn(none)
SplitButtonSplit button: main clickable part next to a drop-down selectorIcon, Text (string), Popup (a PopupList object)ButtonPushedFcn, DynamicPopupFcnButtonPushed, DropDownPerformed (undocumented)
GalleryA gallery of selectable options, displayed in-panelMinColumnCount (integer), MaxColumnCount (integer), Popup (a GalleryPopup object), TextOverlay (string)(none)(none)
DropDownGalleryButtonA gallery of selectable options, displayed as a drop-downMinColumnCount (integer), MaxColumnCount (integer), Popup (a GalleryPopup object), TextOverlay (string)(none)(none)

In addition to the control properties listed in the table above, all toolstrip controls share some common properties:

  • Description – a string that is shown in a tooltip when you hover the mouse over the control
  • Enabled – a logical value (default: true) that controls whether we can interact with the control. A disabled control is typically grayed-over. Note that the value is a logical true/false, not ‘on’/’off’
  • Tag – a string that can be used to uniquely identify/locate the control via their container’s find(tag) and findAll(tag) methods. Can contain spaces and special symbols – does not need to be a valid Matlab identifier
  • Children – contains a list of sub-component (if any); useful with complex controls
  • Parent – the handle of the container that contains the control
  • Type – the type of control, typically its class-name
  • Mnemonic – an undocumented string property, currently unused (?)
  • Shortcut – an undocumented string property, currently unused (?)

The EmptyControl, Button, ToggleButton and CheckBox controls were discussed in an earlier post of this miniseries. The bottom 6 selection controls (ListBox, DropDown, DropDownButton, SplitButton, Gallery and DropDownGalleryButton) will be discussed in the next post. The rest of the controls are described below.

Button groups

A ButtonGroup binds several CheckBox and ToggleButton components such that only one of them is selected (pressed) at any point in time. For example:

hSection = hTab.addSection('Radio-buttons');
hColumn = hSection.addColumn();
 
% Grouped RadioButton controls
hButtonGroup = ButtonGroup;
hRadio = RadioButton(hButtonGroup, 'Option choice #1');
hRadio.ValueChangedFcn = @ValueChangedCallback;
hColumn.add(hRadio);
 
hRadio = RadioButton(hButtonGroup, 'Option choice #2');
hRadio.ValueChangedFcn = @ValueChangedCallback;
hRadio.Value = true;
hColumn.add(hRadio);

Toolstrip ButtonGroup

Toolstrip ButtonGroup

Note that unlike the uibuttongroup object in “standard” figure GUI, the toolstrip’s ButtonGroup object does not have a SelectionChangedFcn callback property (or corresponding event). Instead, we need to set the ValueChangedFcn callback property (or listen to the ValueChanged event) separately for each individual control. This is really a shame – I think it would make good design sense to have a SelectionChangedFcn callback at the ButtonGroup level, as we do for uibuttongroup (in addition to the individual control callbacks).

Also note that the internal documentation of ButtonGroup has an error – it provides an example usage with RadioButton that has its constructor inputs switched: the correct constructor is RadioButton(hButtonGroup,labelStr). On the other hand, for ToggleButton, the hButtonGroup input is the [optional] 3rd input arg of the constructor: ToggleButton(labelStr,Icon,hButtonGroup). I think that it would make much more sense for the RadioButton constructor to follow the documentation and the style of ToggleButton and make the hButtonGroup input the last (2nd, optional) input arg, rather than the 1st. In other words, it would make more sense for RadioButton(labelStr,hButtonGroup), but unfortunately this is currently not the case.

Label, EditField and TextArea

A Label control is a simple non-clickable text label with an optional Icon, whose text is controlled via the Text property. The label’s alignment is controlled by the containing column’s HorizontalAlignment property.

An EditField is a single-line edit-box. Its string contents can be fetched/updated via the Value property, and when the user updates the edit-box contents the ValueChangedFcn callback is invoked (upon each modification of the string, i.e. every key-click). This is a pretty simple control actually.

The EditField control has a hidden (undocumentented) settable property called PlaceholderText, which presumably aught to display a gray initial prompt within the editbox. However, as far as I could see this property has no effect (perhaps, as the name implies, it is a place-holder for a future functionality…).

A TextArea is another edit-box control, but enables entering multiple lines of text, unlike EditField which is a single-line edit-box. TextArea too is a very simple control, having a settable Value string property and a ValueChangedFcn callback. Whereas EditField controls, being single-line, would typically be included in 2- or 3-element toolstrip columns, the TextArea would typically be placed in a single-element column, so that it would span the entire column height.

A peculiarity of toolstrip columns is that unless you specify their Width property, the internal controls are displayed with a minimal width (the width is only controllable at the column level, not the control-level). This is especially important with EditField and TextArea controls, which are often empty by default, causing their assigned width to be minimal (only a few pixels). This is corrected by setting their containing column’s Width:

% EditField controls
column1 = hSection.addColumn('HorizontalAlignment','right');
column1.add(Label('Yaba:'))
column1.add(Label('Daba doo:'))
 
column2 = hSection.addColumn('Width',70);
column2.add(EditField);
column2.add(EditField('Initial text'));
 
% TextArea control
column3 = hSection.addColumn('Width',90);
hEdit = TextArea;
hEdit.ValueChangedFcn = @ValueChangedCallback;
column3.add(hEdit);

Toolstrip Label, EditField and TextArea

Toolstrip Label, EditField and TextArea

Spinner

Spinner is a single-line numeric editbox that has an attached side-widget where you can increase/decrease the editbox value by a specified amount, subject to predefined min/max values. If you try to enter an illegal value, Matlab will beep and the editbox will revert to its last acceptable value. You can only specify a NumberFormat of ‘integer’ or ‘double’ (default: ‘integer’) and a DecimalFormat which is a string composed of the number of sub-decimal digits to display and the format (‘e’ or ‘f’). For example, DecimalFormat=’4f’ will display 4 digits after the decimal in floating-point format (‘e’ means engineering format). Here is a short usage example (notice the different ways that we can set the callbacks):

hColumn = hSection.addColumn('Width',100);
 
% Integer spinner (-100 : 10 : 100)
hSpinner = Spinner([-100 100], 0);  % [min,max], initialValue
hSpinner.Description = 'this is a tooltip description';
hSpinner.StepSize = 10;
hSpinner.ValueChangedFcn = @ValueChangedCallback;
hColumn.add(hSpinner);
 
% Floating-point spinner (-10 : 0.0001 : 10)
hSpinner = Spinner([-10 10], pi);  % [min,max], initialValue
hSpinner.NumberFormat = 'double';
hSpinner.DecimalFormat = '4f';
hSpinner.StepSize = 1e-4;
addlistener(hSpinner,'ValueChanged', @ValueChangedCallback);
addlistener(hSpinner,'ValueChanging',@ValueChangingCallback);
hColumn.add(hSpinner);

Toolstrip Spinner

Toolstrip Spinner

A logical extension of the toolstrip spinner implementation would be for non-numeric spinners, as well as custom Value display formatting. Perhaps this will become available at some future Matlab release.

Slider

Slider is a horizontal ruler on which you can move a knob from the left (min Value) to the right (max Value). The ticks and labels are optional and customizable. Here is a simple example showing a plain slider (values between 0-100, initial value 70, ticks every 5, labels every 20, step size 1), followed by a custom slider (notice again the different ways that we can set the callbacks):

hColumn = hSection.addColumn('Width',200);
 
hSlider = Slider([0 100], 70);  % [min,max], initialValue
hSlider.Description = 'this is a tooltip';
tickVals = 0 : 20 : 100;
hSlider.Labels = [compose('%d',tickVals); num2cell(tickVals)]';  % {'0',0; '20',20; ...}
hSlider.Ticks = 21;  % =numel(0:5:100)
hSlider.ValueChangedFcn = @ValueChangedCallback;
hColumn.add(hSlider);
 
hSlider = Slider([0 100], 40);  % [min,max], initialValue
hSlider.Labels = {'Stop' 0; 'Slow' 20; 'Fast' 50; 'Too fast' 75; 'Crash!' 100};
try hSlider.UseSmallFont = true; catch, end  % UseSmallFont was only added in R2018b
hSlider.Ticks = 11;  % =numel(0:10:100)
addlistener(hSlider,'ValueChanged', @ValueChangedCallback);
addlistener(hSlider,'ValueChanging',@ValueChangingCallback);
hColumn.add(hSlider);

Toolstrip Slider

Toolstrip Slider

Toolstrip miniseries roadmap

The next post will discuss complex selection components, including listbox, drop-down, split-button, and gallery.

Following that, I plan to discuss toolstrip collapsibility, the ToolPack framework, docking layout, DataBrowser panel, QAB (Quick Access Bar), underlying Java controls, and adding toolstrips to figures – not necessarily in this order.
Matlab toolstrips can be a bit complex, so I plan to proceed in small steps, each post building on top of its predecessors.

If you would like me to assist you in building a custom toolstrip or GUI for your Matlab program, please let me know.

]]>
https://undocumentedmatlab.com/blog_old/matlab-toolstrip-part-6-complex-controls/feed 4
Matlab toolstrip – part 4 (control customization)https://undocumentedmatlab.com/blog_old/matlab-toolstrip-part-4-control-customization https://undocumentedmatlab.com/blog_old/matlab-toolstrip-part-4-control-customization#respond Sun, 30 Dec 2018 16:00:00 +0000 https://undocumentedmatlab.com/?p=8110 Related posts:
  1. Matlab toolstrip – part 6 (complex controls) Multiple types of customizable controls can be added to Matlab toolstrips...
  2. Figure window customizations Matlab figure windows can be customized in numerous manners using the underlying Java Frame reference. ...
  3. Matlab toolstrip – part 2 (ToolGroup App) Matlab users can create custom Apps with toolstrips and docked figures. ...
  4. Matlab toolstrip – part 3 (basic customization) Matlab toolstrips can be created and customized in a variety of ways. ...
]]>
In a previous post I showed how we can create custom Matlab app toolstrips. Toolstrips can be a bit complex to develop so I’m trying to proceed slowly, with each post in the miniseries building on the previous posts. I encourage you to review the earlier posts in the Toolstrip miniseries before reading this post. In today’s post we continue the discussion of the toolstrip created in the previous post:
Toolstrip example (basic controls)

Toolstrip example (basic controls)

Today’s post will show how to attach user-defined functionality to toolstrip components, as well as some additional customizations. At the end of today’s article, you should be able to create a fully-functional custom Matlab toolstrip. Today’s post will remain within the confines of a Matlab “app”, i.e. a tool-group that displays docked figures. Future posts will discuss lower-level toolstrip mechanisms, that enable advanced customizations as well as integration in legacy (Java-based, even GUIDE-created) Matlab figures.

Control callbacks

Controls are useless without settable callbacks that affect the program state based on user interactions. There are two different mechanisms for setting callbacks for Matlab toolstrip controls. Refer to the example in the previous post:

  1. Setting the control’s callback property or properties – the property names differ across components (no, for some reason it’s never as simple as Callback in standard uicontrols). For example, the main action callback for push-buttons is ButtonPushedFcn, for toggle-buttons and checkboxes it’s ValueChangedFcn and for listboxes it’s . Setting the callback is relatively easy:
    hColorbar.ValueChangedFcn = @toggleColorbar;
     
    function toggleColorbar(hAction,hEventData)
        if hAction.Selected
            colorbar;
        else
            colorbar('off');
        end
    end

    The hAction object that is passed to the callback function as the first input arg contains various fields of interest, but for some reason the most important object property (Value) is renamed as the Selected property (most confusing). Also, a back-reference to the originating control (hColorbar in this example), which is important for many callbacks, is also missing (and no – I couldn’t find it in the hidden properties either):

    >> hAction
    hAction = 
      Action with properties:
     
                Description: 'Toggle colorbar display'
                    Enabled: 1
                   Shortcut: ''
                   Selected: 1
            QuickAccessIcon: []
        SelectionChangedFcn: @toggleColorbar
                       Text: 'Colorbar'
            IsInQuickAccess: 0
                ButtonGroup: []
                       Icon: [1×1 matlab.ui.internal.toolstrip.Icon]
     
    >> hEventData
    hEventData = 
      ToolstripEventData with properties:
     
        EventData: [1×1 struct]
           Source: [0×0 handle]
        EventName: ''
     
    >> hEventData.EventData
    ans = 
      struct with fields:
     
        Property: 'Value'
        NewValue: 1
        OldValue: 0

    Note that hEventData.Source is an empty handle for some unknown reason.

    The bottom line is that to reference the button state using this callback mechanism we need to either:

    1. Access hAction‘s Selected property which stands-in for the originating control’s Value property (this is what I have shown in the short code snippet above)
    2. Access hEventData.EventData and use its reported Property, NewValue and OldValue fields
    3. Pass the originating control handle as an extra (3rd) input arg to the callback function, and then access it from within the callback. For example:
      hColorbar.ValueChangedFcn = {@toggleColorbar, hColorbar};
       
      function toggleColorbar(hAction,hEventData,hButton)
          if hButton.Value %hAction.Selected
              colorbar;
          else
              colorbar('off');
          end
      end
  2. As an alternative, we can use the addlistener function to attach a callback to control events. Practically all toolstrip components expose public events that can be listened-to using this mechanism. In most cases the control’s callback property name(s) closely follow the corresponding events. For example, for buttons we have the ValueChanged event that corresponds to the ValueChangedFcn property. We can use listeners as follows:
    hCheckbox.addlistener('ValueChanged',@toggleLogY);
     
    function toggleLogY(hCheckbox,hEventData)
        if hCheckbox.Value, type = 'log'; else, type = 'linear'; end
        set(gca, 'XScale',type, 'YScale',type, 'ZScale',type);
    end

    Note that when we use the addlistener mechanism to attach callbacks, we don’t need any of the tricks above – we get the originating control handle as the callback function’s first input arg, and we can access it directly.

    Unfortunately, we cannot pass extra args to the callback that we specify using addlistener (this seems like a trivial and natural thing to have, for MathWorks’ attention…). In other words, addlistener only accepts a function handle as callback, not a cell array. To bypass this limitation in uicontrols, we typically add the extra parameters to the control’s UserData or ApplicationData properties (the latter via the setappdata function). But alas – toolstrip components have neither of these properties, nor can we add them in runtime (as with for other GUI controls). So we need to find some other way to pass these extra values, such as using global variables, or making the callback function nested so that it could access the parent function’s workspace.

Additional component properties

Component text labels, where relevant, can be set using the component’s Text property, and the tooltip can be set via the Description property. As I noted in my previous post, I believe that this is an unfortunate choice of property names. In addition, components have control-specific properties such as Value (checkboxes and toggle buttons). These properties can generally be modified in runtime, in order to reflect the program state. For example, we can disable/enable controls, and modify their label, tooltip and state depending on the control’s new state and the program state in general.

The component icon can be set via the Icon property, where available (for example, buttons have an icon, but checkboxes do not). There are several different ways in which we can set this Icon. I will discuss this in detail in the following post; in the meantime you can review the usage examples in the previous post.

There are a couple of additional hidden component properties that seem promising, most notably Shortcut and Mnemonic (the latter (Mnemonic) is also available in Section and Tab, not just in components). Unfortunately, at least as of R2018b these properties do not seem to be connected yet to any functionality. In the future, I would expect them to correspond to keyboard shortcuts and underlined mnemonic characters, as these functionalities behave in standard menu items.

Accessing the underlying Java control

As long as we’re not displaying the toolstrip on a browser page (i.e., inside a uifigure or Matlab Online), the toolstrip is basically composed of Java Swing components from the com.mathworks.toolstrip.components package (such as TSButton or TSCheckBox). I will discuss these Java classes and their customizations in a later post, but for now I just wish to show how to access the underlying Java component of any Matlab MCOS control. This can be done using a central registry of toolstrip components (so-called “widgets”), which is accessible via the ToolGroup‘s hidden ToolstripSwingService property, and then via each component’s hidden widget Id. For example:

>> widgetRegistry = hToolGroup.ToolstripSwingService.Registry;
>> jButton = widgetRegistry.getWidgetById(hButton.getId)  % get the hButton's underlying Java control
ans =
com.mathworks.toolstrip.components.TSToggleButton[,"Colorbar",layout<>,NORMAL]

We can now apply a wide variety of Java-based customizations to the retrieved jButton, as I have shown in many other articles on this website over the past decade.

Another way to access the toolstrip Java component hierarchy is via hToolGroup.Peer.get(tabIndex).getComponent. This returns the top-level Java control representing the tab whose index in tabIndex (0=left-most tab):

>> jToolGroup = hToolGroup.Peer;  % or: =hToolGroup.ToolstripSwingService.SwingToolGroup;
>> jDataTab = jToolGroup.get(0).getComponent;  % Get tab #0 (first tab: "Data")
>> jDataTab.list   % The following is abridged for brevity
com.mathworks.toolstrip.impl.ToolstripTabContentPanel[tab0069230a-52b0-4973-b025-2171cd96301b,0,0,831x93,...]
 SectionWrapper(section54fb084c-934d-4d31-9468-7e4d66cd85e5)
  com.mathworks.toolstrip.impl.ToolstripSectionComponentWithHeader[,0,0,241x92,...]
   com.mathworks.toolstrip.components.TSPanel[section54fb084c-934d-4d31-9468-7e4d66cd85e5,,layout<HORIZONTAL>,NORMAL]
    TSColumn -> layout<> :
     com.mathworks.toolstrip.components.TSButton[,"Refresh all",layout<>,NORMAL]
    TSColumn -> layout<> :
     com.mathworks.toolstrip.components.TSButton[,"Refresh X,Y",layout<>,NORMAL]
     com.mathworks.toolstrip.components.TSButton[,"Refresh Y,Z",layout<>,NORMAL]
    TSColumn -> layout<> :
     com.mathworks.toolstrip.components.TSButton[,"Refresh X",layout<>,NORMAL]
     com.mathworks.toolstrip.components.TSButton[,"Refresh Y",layout<>,NORMAL]
     com.mathworks.toolstrip.components.TSButton[,"Refresh Z",layout<>,NORMAL]
 SectionWrapper(sectionebd8ab95-fd33-4a3d-8f24-152589713994)
  com.mathworks.toolstrip.impl.ToolstripSectionComponentWithHeader[,0,0,159x92,...]
   com.mathworks.toolstrip.components.TSPanel[sectionebd8ab95-fd33-4a3d-8f24-152589713994,,layout<HORIZONTAL>,NORMAL]
    TSColumn -> layout<> :
     com.mathworks.toolstrip.components.TSCheckBox[,"Axes borders",layout<>,NORMAL]
     com.mathworks.toolstrip.components.TSCheckBox[,"Log scaling",layout<>,NORMAL]
     com.mathworks.toolstrip.components.TSCheckBox[,"Inverted Y",layout<>,NORMAL]
 SectionWrapper(section01995bfd-61de-490f-aa22-de50bae1af75)
  com.mathworks.toolstrip.impl.ToolstripSectionComponentWithHeader[,0,0,125x92,...]
   com.mathworks.toolstrip.components.TSPanel[section01995bfd-61de-490f-aa22-de50bae1af75,,layout<HORIZONTAL>,NORMAL]
    TSColumn -> layout<> :
     com.mathworks.toolstrip.components.TSToggleButton[,"Legend",layout<>,NORMAL]
    TSColumn -> layout<> :
     com.mathworks.toolstrip.components.TSLabel[null," ",layout<>,NORMAL]
     com.mathworks.toolstrip.components.TSToggleButton[,"Colorbar",layout<>,NORMAL]
     com.mathworks.toolstrip.components.TSLabel[null," ",layout<>,NORMAL]
 com.mathworks.mwswing.MJButton[toolstrip.header.collapseButton,808,70,20x20,...]

Toolstrip miniseries roadmap

The next post will discuss icons, for both toolstrip controls as well as the ToolGroup app window.

I plan to discuss complex components in subsequent posts. Such components include button-group, drop-down, listbox, split-button, slider, popup form, gallery etc.

Following that, my plan is to discuss toolstrip collapsibility, the ToolPack framework, docking layout, DataBrowser panel, QAB (Quick Access Bar), underlying Java controls, and adding toolstrips to figures – not necessarily in this order.

Have I already mentioned that Matlab toolstrips can be a bit complex?

If you would like me to assist you in building a custom toolstrip or GUI for your Matlab program, please let me know.

Happy New Year, everyone!

]]>
https://undocumentedmatlab.com/blog_old/matlab-toolstrip-part-4-control-customization/feed 0
IP address input controlhttps://undocumentedmatlab.com/blog_old/ip-address-input-control https://undocumentedmatlab.com/blog_old/ip-address-input-control#comments Wed, 31 Jan 2018 16:16:12 +0000 https://undocumentedmatlab.com/?p=7313 Related posts:
  1. FindJObj GUI – display container hierarchy The FindJObj utility can be used to present a GUI that displays a Matlab container's internal Java components, properties and callbacks....
  2. FindJObj – find a Matlab component’s underlying Java object The FindJObj utility can be used to access and display the internal components of Matlab controls and containers. This article explains its uses and inner mechanism....
  3. Uitable sorting Matlab's uitables can be sortable using simple undocumented features...
  4. Tri-state checkbox Matlab checkboxes can easily be made to support tri-state functionality....
]]>
A few weeks ago, a user posted a question on Matlab Answers, asking whether it is possible to implement a text input control that accepts and validates an IP address (for example, ‘192.168.1.101’). While doing this using purely documented Matlab code is indeed possible (for those of us who are masochistically inclined and/or have nothing else to do with their spare time), a very simple-to-use and polished-looking solution is to use an undocumented built-in Matlab control.

The solution is based on the fact that Matlab comes with a huge set of professional Java-based controls by JideSoft, bundled in various JAR libraries within the %matlabroot%/java/jarext/jide Matlab installation folder. For our specific purposes (an IP-address entry/display control), we are interested in the com.jidesoft.field.IPTextField control (online documentation), which is part of the JIDE Grids library (%matlabroot%/java/jarext/jide/jide-grids.jar). We can use it as follows:

jIPField = com.jidesoft.field.IPTextField('255.255.255.0');  % set default IP
[jIPField, hContainer] = javacomponent(jIPField, [10,10,120,20], hParent);  % hParent: panel/figure handle

IPTextField control in a Matlab GUI

IPTextField control in a Matlab GUI

You can modify the position/size of the text-field in the javacomponent call above, or by modifying the Position / Units properties of the returned hContainer.

We can retrieve the IP text/numeric values using:

vals = jIPField.getValue';         % 1x4 uint32 array => [255,255,255,0]
vals = cell(jIPField.getRawText)'; % 1x4 string cells => {'255','255','255','0'} 
ip   = char(jIPField.getText);     % entire IP string => '255.255.255.0'

The IPTextField component auto-validates the IP values, ensuring that the displayed IP is always valid (for example, IP components cannot be negative or larger than 255). The component has many other features, including the ability to enable/disable, color or format the IP components etc.

We can set a callback function to process user changes, by setting the component’s *StateChangedCallback* property, for example:

jIPField.StateChangedCallback = @(jComponent,jEventData) disp(jComponent.getValue');

The JIDE libraries that come with Matlab contain numerous other similarly-useful components, including date/time/font/color/file/folder selectors, calendars in various formats, credit-card fields, and many more.

For more information about using the javacomponent function and handling Java components in Matlab GUI, see other posts on this website – particularly those marked with the “JIDE” tag.

Additional discussion of JIDE’s combo-boxes, and JIDE controls in general, is available in Chapter 5 of my Matlab-Java Programming book.

If you need to integrate professional-looking controls such as these in your Matlab GUI, consider hiring my consulting services.

Caution

Remember that JIDE evolves with Matlab, and so JIDE’s online documentation, which refers to the latest JIDE version, may be partially inapplicable if you use an old Matlab version. In any case, Matlab releases always lag the latest JIDE release by at least a year (e.g., Matlab R2017b still uses JIDE v3.4.1 that was released in June 2012 – MathWorks used to update the bundled JIDE libraries to newer versions, but for some reason has stopped doing that in 2013). The older your Matlab, the more such inconsistencies that you may find. For example, I believe that DateSpinnerComboBox only became available around R2010b; similarly, some control properties behave differently (or are missing altogether) in different releases. To determine the version of JIDE that you are currently using in Matlab, run the following (the result can then be compared to JIDE’s official change-log history):

>> com.jidesoft.utils.Lm.getProductVersion
ans =
3.4.1

Note that JIDE is a commercial product. We may not use it without JIDESoft’s permission outside the Matlab environment. It is my understanding however, that we can freely use it within Matlab. Note that this is not legal advise as I am an engineer, not a lawyer. If you have any licensing questions, contact sales@jidesoft.com.

Also note that all of JIDE’s controls use the Java-based figures (that are created using GUIDE or the figure function), and will not work on the new web-based uifigures (created using App Designer or the uifigure function). There is currently no corresponding IP entry/display control for web-based GUIs, and since there is [still] no way to integrate external Javascript/CSS libraries in uifigures, the only resort is to use a plain-vanilla edit-box. If MathWorks would simply open a hook to integrate external JS/CSS libraries, that would enable users to use 3rd-party libraries that have such custom controls and MathWorks would then not need to spend a huge amount of effort to develop multiple UI control variants.

]]>
https://undocumentedmatlab.com/blog_old/ip-address-input-control/feed 3
Customizing uifigures part 3https://undocumentedmatlab.com/blog_old/customizing-uifigures-part-3 https://undocumentedmatlab.com/blog_old/customizing-uifigures-part-3#comments Mon, 27 Nov 2017 15:00:24 +0000 https://undocumentedmatlab.com/?p=7169 Related posts:
  1. Customizing uifigures part 2 Matlab's new web-based uifigures can be customized using custom CSS and Javascript code. ...
  2. 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....
  3. FindJObj – find a Matlab component’s underlying Java object The FindJObj utility can be used to access and display the internal components of Matlab controls and containers. This article explains its uses and inner mechanism....
  4. FindJObj GUI – display container hierarchy The FindJObj utility can be used to present a GUI that displays a Matlab container's internal Java components, properties and callbacks....
]]>
As I have repeatedly posted in recent years, Matlab is advancing towards web-based GUI. The basic underlying technology is more-or-less stable: an HTML/Javascript webpage that is created-on-the-fly and rendered in a stripped-down browser window (based on Chromium-based jxBrowser in recent years). However, the exact mechanism by which the controls (“widgets”) are actually converted into visible components (currently based on the Dojo toolkit and its Dijit UI library) and interact with Matlab (i.e., the internal Matlab class structures that interact with the browser and Dojo) is still undergoing changes and is not quite as stable.

Customization hacks reported on this blog last year (part 1, part 2) may fail in some cases due to the changing nature of the undocumented internals. Some examples are the way by which we can extract the uifigure’s URL (which changed in R2017a), the ability to display and debug uifigures in a standard webbrowser with associated dev tools (which seems to have stopped working in R2017b), and the way by which we can extract the Dijit reference of displayed uicontrols.

Greatly assisting in this respect is Iliya Romm, who was the guest blogger for part 2 of this series last year. Iliya co-authored the open-source (GitHub) mlapptools toolbox, which enables accessing and customizing uifigure components using standard CSS, without users having to bother about the ugly hacks discussed in the previous parts of the series. This toolbox is really just a single Matlab class (mlapptools), contained within a single m-file (mlapptools.m). In addition to this class, the toolbox includes a README.md mark-down usage documentation, and two demo functions, DOMdemoGUI.m and TableDemo.m.

Here is the effect of using TableDemo, that shows how we can customize individual uitable cells (each uitable cell is a separate Dijit widget that can be customized individually):

CSS customizations of uifigure components

CSS customizations of uifigure components


The mlapptools class contains several static methods that can be used individually:

  • textAlign(uielement, alignment) – Modify text horizontal alignment ('left', 'center', 'right', 'justify' or 'initial')
  • fontWeight(uielement, weight) – Modify font weight ('normal', 'bold', 'bolder', 'lighter' or 'initial'), depending on availability in the font-face used
  • fontColor(uielement, color) – Modify font color (e.g. 'red', '#ff0000', 'rgb(255,0,0)' or other variants)
  • setStyle(uielement, styleAttr, styleValue) – Modify a specified CSS style attribute
  • aboutDojo() – Return version information about the Dojo toolkit
  • getHTML(hFig) – Return the full HTML code of a uifigure
  • getWebWindow(hFig) – Return a webwindow handle from a uifigure handle
  • getWebElements (hControl) – Return a webwindow handle and a widget ID for the specified uicontrol handle
  • getWidgetList(hFig, verboseFlag) – Return a cell-array of structs containing information about all widgets in the uifigure
  • getWidgetInfo(hWebwindow, widgetId, verboseFlag) – Return information about a specific dijit widget
  • setTimeout(hFig, seconds) – Override the default timeout (=5 secs) for dojo commands, for a specific uifigure

A few simple usage examples:

mlapptools.fontColor(hButton,'red')  % set red text color
mlapptools.fontWeight(hButton,'bold')  % set bold text font
mlapptools.setStyle(hButton,'border','2px solid blue')  % add a 2-pixel solid blue border
mlapptools.setStyle(hButton,'background-image','url(https://www.mathworks.com/etc/designs/mathworks/img/pic-header-mathworks-logo.svg)')  % add background image

Once you download mlapptools and add its location to the Matlab path, you can use it in any web-based GUI that you create, either programmatically or with Add-Designer.

The mlapptools is quite well written and documented, so if you are interested in the inner workings I urge you to take a look at this class’s private methods. For example, to understand how a Matlab uicontrol handle is converted into a Dojo widget-id, which is then used with the built-in dojo.style() Javascript function to modify the CSS attributes of the HTML <div> or <span> that are the control’s visual representation on the webpage. An explanation of the underlying mechanism can be found in part 2 of this series of articles on uifigure customizations. Note that the mlapptools code is newer than the article and contains some new concepts that were not covered in that article, for example searching through Dijit’s registry of displayed widgets.

Note: web-based GUI is often referred to as “App-Designed” (AD) GUI, because using the Matlab App Designer is the typical way to create and customize such GUIs. However, just as great-looking GUIs could be created programmatically rather than with GUIDE, so too can web-based GUIS be created programmatically, using regular built-in Matlab commands such as uifigure, uibutton and uitable (an example of such programmatic GUI creation can be found in Iliya’s TableDemo.m, discussed above). For this reason, I believe that the new GUIs should be referred to as “uifigures” or “web GUIs”, and not as “AD GUIs”.

If you have any feature requests or bugs related to mlapptools, please report them on its GitHub issues page. For anything else, please add a comment below.

]]>
https://undocumentedmatlab.com/blog_old/customizing-uifigures-part-3/feed 5
GUI formatting using HTMLhttps://undocumentedmatlab.com/blog_old/gui-formatting-using-html https://undocumentedmatlab.com/blog_old/gui-formatting-using-html#comments Wed, 05 Apr 2017 20:26:44 +0000 https://undocumentedmatlab.com/?p=6877 Related posts:
  1. Icon images & text in Matlab uicontrols HTML can be used to add image icons to Matlab listbox and popup (drop-down) controls. ...
  2. Spicing up Matlab uicontrol tooltips Matlab uicontrol tooltips can be spiced-up using HTML and CSS, including fonts, colors, tables and images...
  3. Multi-line uitable column headers Matlab uitables can present long column headers in multiple lines, for improved readability. ...
  4. Rich-contents log panel Matlab listboxes and editboxes can be used to display rich-contents HTML-formatted strings, which is ideal for log panels. ...
]]>
As I’ve mentioned several times in the past, HTML can be used for simple formatting of GUI controls, including font colors/sizes/faces/angles. With a bit of thought, HTML (and some CSS) can also be used for non-trivial formatting, that would otherwise require the use of Java, such as text alignment, background color, and using a combination of text and icons in the GUI control’s contents.

Alignment

For example, a question that I am often asked (latest example) is whether it is possible to left/center/right align the label within a Matlab button, listbox or table. While Matlab does not (yet) have properties that control alignment in uicontrols, we can indeed use HTML for this. There’s a catch though: if we simply tried to use <div align="left">…, it will not work. No error will be generated but we will not see any visible left-alignment. The reason is that internally, the text is contained within a snugly-fitting box. Aligning anything within a tight-fitting box obviously has no effect.

To solve the problem, we need to tell Matlab (or rather, the HTML interpreter used by the underlying Java control) to widen this internal box. One way to do this is to specify the width of the div tag, which can be enormous in order to span the entire available apace (<div width="999px" align="left">…). Another method is to simulate a simple HTML table that contains a single cell that holds the text, and then tell HTML the table cell’s width:

hButton.String   = '<html><tr><td width=9999 align=left>Left-aligned';  % left-align within a button
hTable.Data{2,1} = '<html><tr><td width=9999 align=right>And right';   % right-align within a specific uitable cell

centered (default) button label   right-aligned button label

Centered (default) and right-aligned button labels

Non-default alignment of uitable cells

Non-default alignment of uitable cells

I discussed the specific aspect of uicontrol content alignment in another post last year.

Background color

The same problem (and solution) applies to background colors: if we don’t enlarge the snugly-fitting internal bounding-box, any HTML bgcolor that we specify would only be shown under the text (i.e., within the internal box’s confines). In order to display bgcolor across the entire control/cell width, we need to enlarge the internal box’s width (the align and bgcolor tags can of course be used together):

hButton.String   = '<html><tr><td width=9999 bgcolor=#ffff00>Yellow';  % bgcolor within a button
hTable.Data{2,1} = '<html><tr><td width=9999 bgcolor=#ffff00>Yellow';  % bgcolor within a specific uitable cell

CSS

We can also use simple CSS, which provides more formatting customizability than plain HTML:

hTable.Data{2,1} = '<html><tr><td width=9999 style="background-color:yellow">Yellow';

HTML/CSS formatting is a poor-man’s hack. It is very crude compared to the numerous customization options available via Java. However, it does provide a reasonable solution for many use-cases, without requiring any Java. I discussed the two approaches for uitable cell formatting in this post.

[Non-]support in uifigures

Important note: HTML formatting is NOT [yet] supported by the new web-based uifigures. While uifigures can indeed be hacked with HTML/CSS content (details), this is not an easy task. Since it should be trivially easy for MathWorks to enable HTML content in the new web-based uifigures, I implore anyone who uses HTML in their Matlab GUI to let MathWorks know about it so that they could prioritize this R&D effort into an upcoming Matlab release. You can send an email to Eric.Sargent at mathworks.com, who handles such aspects in MathWorks’ R&D efforts to transition from Java-based GUIs to web-based ones. In my previous post I spotlit MathWorks user-feedback surveys about users’ use of Java GUI aspects, aimed in order to migrate as many of the use-cases as possible onto the new web-based framework. HTML/CSS support is a natural by-product of the fact that Matlab’s non-web-based GUI is based on Java Swing components (that inherently support HTML/CSS). But unfortunately the MathWorks surveys are specific to the javacomponent function and the figure’s JavaFrame property. In other words, many users might be using undocumented Java aspects by simply using HTML content in their GUI, without ever realizing it or using javacomponent. So I think that in this case a simple email to Eric.Sargent at mathworks.com to let him know how you’re using HTML would be more useful. Maybe one day MathWorks will be kind enough to post a similar survey specific to HTML support, or maybe one day they’s just add the missing HTML support, if only to be done with my endless nagging. :-)

p.s. – I am well aware that we can align and bgcolor buttons in AppDesigner. But we can’t do this with individual table/listbox cells, and in general we can’t use HTML within uifigures without extensive hacks. I merely used the simple examples of button and uitable cell formatting in today’s post to illustrate the issue. So please don’t get hung up on the specifics, but rather on the broader issue of HTML support in uifigures.

And in the meantime, for as long as non-web-based GUI is still supported in Matlab, keep on enjoying the benefits that HTML/CSS provides.

Automated bug-fix emails

In an unrelated matter, I wish to express my Kudos to the nameless MathWorkers behind the scenes who, bit by bit, improve Matlab and the user experience: Over the years I’ve posted a few times my frustrations with the opaqueness of MathWorks’ bug-reporting mechanism. One of my complaints was that users who file bugs are not notified when a fix or workaround becomes available. That at least seems to have been fixed now. I just received a seemingly-automated email notifying me that one of the bugs that I reported a few years ago has been fixed. This is certainly a good step in the right direction, so thank you!

Happy Passover/Easter to all!

]]>
https://undocumentedmatlab.com/blog_old/gui-formatting-using-html/feed 6
Icon images & text in Matlab uicontrolshttps://undocumentedmatlab.com/blog_old/icon-images-in-matlab-uicontrols https://undocumentedmatlab.com/blog_old/icon-images-in-matlab-uicontrols#comments Wed, 28 Sep 2016 10:28:04 +0000 https://undocumentedmatlab.com/?p=6687 Related posts:
  1. Rich-contents log panel Matlab listboxes and editboxes can be used to display rich-contents HTML-formatted strings, which is ideal for log panels. ...
  2. Spicing up Matlab uicontrol tooltips Matlab uicontrol tooltips can be spiced-up using HTML and CSS, including fonts, colors, tables and images...
  3. Aligning uicontrol contents Matlab uicontrols can often be customized using plain HTML/CSS, without need for advanced Java. ...
  4. GUI integrated browser control A fully-capable browser component is included in Matlab and can easily be incorporated in regular Matlab GUI applications. This article shows how....
]]>
One of my consulting clients recently asked me if I knew any builtin Matlab GUI control that could display a list of colormap names alongside their respective image icons, in a listbox or popup menu (drop-down/combo-box):

Matlab listbox with icon images   Matlab popup menu (dropdown/combobox) with icon images

Matlab listbox (left) & popup menu (right) with icon images

My initial thought was that this should surely be possible, since Colormap is a documented figure property, that should therefore be listed inside the inspector window, and should therefore have an associated builtin Java control for the dropdown (just like other inspector controls, which are part of the com.mathworks.mlwidgets package, or possibly as a standalone control in the com.mathworks.mwswing package). To my surprise it turns out that for some unknown reason MathWorks neglected to add the Colormap property (and associated Java controls) to the inspector. This property is fully documented and all, just like Color and other standard figure properties, but unlike them Colormap can only be modified programmatically, not via the inspector window. Matlab does provide the related colormapeditor function and associated dialog window, but I would have expected a simple drop-down of the standard builtin colormaps to be available in the inspector. Anyway, this turned out to be a dead-end.

It turns out that we can relatively easily implement the requested listbox/combo-box using a bit of HTML magic, as I explained last week. The basic idea is for each of the listbox/combobox items to be an HTML string that contains both an <img> tag for the icon and the item label text. For example, such a string might contain something like this (parula is Matlab’s default colormap in HG2, starting in R2014b):

<html><img src="http://www.mathworks.com/help/matlab/ref/colormap_parula.png">parula

parula colormap image

parula colormap image

Of course, it would be a bit inefficient for each of the icons to be fetched from the internet. Luckily, the full set of Matlab documentation is typically installed on the local computer as part of the standard Matlab installation, beneath the docroot folder (e.g., C:\Program Files\Matlab\R2016b\help). In our specific case, the parula colormap image is located in:

imageFilename = [docroot, '/matlab/ref/colormap_parula.png']

Note that for a local image to be accepted by HTML, it needs to follow certain conventions. In our case, the HTML string for displaying the above image is:

<html><img src="file:///C:/Program%20Files/Matlab/R2016b/help/matlab/ref/colormap_parula.png">parula

Warning: it’s easy when dealing with HTML images in Matlab to get the format confused, resulting in a red-x icon. I discussed this issue some 4 years ago, which is still relevant.

How can we get the list of available builtin colormaps? The standard Matlab way of doing this would be something like this:

>> possibleColormaps = set(gcf,'Colormap')
possibleColormaps = 
     {}

but as we can see, for some unknown reason (probably another MathWorks omission), Matlab does not list the names of its available builtin colormaps.

Fortunately, all the builtin colormaps have image filenames that follow the same convention, which make it easy to get this list by simply listing the names of the relevant files, from which we can easily create the necessary HTML strings:

>> iconFiles = dir([docroot, '/matlab/ref/colormap_*.png']);
 
>> colormapNames = regexprep({iconFiles.name}, '.*_(.*).png', '$1')
colormapNames =  
  Columns 1 through 9
    'autumn'    'bone'    'colorcube'    'cool'    'copper'    'flag'    'gray'    'hot'    'hsv'
  Columns 10 through 18
    'jet'    'lines'    'parula'    'pink'    'prism'    'spring'    'summer'    'white'    'winter'
 
>> htmlStrings = strcat('<html><img width=200 height=10 src="file:///C:/Program%20Files/Matlab/R2016a/help/matlab/ref/colormap_', colormapNames', '.png">', colormapNames')
str = 
    '<html><img width=200 height=10 src="file:///C:/Program%20Files/Matlab/R2016a/help/matlab/ref/colormap_autumn.png">autumn'
    '<html><img width=200 height=10 src="file:///C:/Program%20Files/Matlab/R2016a/help/matlab/ref/colormap_bone.png">bone'
    '<html><img width=200 height=10 src="file:///C:/Program%20Files/Matlab/R2016a/help/matlab/ref/colormap_colorcube.png">colorcube'
    ...
 
>> hListbox = uicontrol(gcf, 'Style','listbox', 'Units','pixel', 'Pos',[10,10,270,200], 'String',htmlStrings);
>> hPopup   = uicontrol(gcf, 'Style','popup',   'Units','pixel', 'Pos',[10,500,270,20], 'String',htmlStrings);

…which results in the screenshots at the top of this post.

Note how I scaled the images to 10px high (so that the labels would be shown and not cropped vertically) and 200px wide (so that it becomes narrower than the default 434px). There’s really no need in this case for the full 434×27 image size – such flat images scale very nicely, even when their aspect ratio is not preserved. You can adjust the height and width values for a best fit with you GUI.

Unfortunately, it seems that HTML strings are not supported in the new web-based uifigure controls. This is not really Matlab’s fault because the way to customize labels in HTML controls is via CSS: directly embedding HTML code in labels does not work (it’s a Java-Swing feature, not a browser feature). I really hope that either HTML or CSS processing will be enabled for web-based uicontrol in a future Matlab release, because until that time uifigure uicontrols will remain seriously deficient compared to standard figure uicontrols. Until then, if we must use uifigures and wish to customize our labels or listbox items, we can directly access the underlying web controls, as Iliya explained here.


A blog reader recently complained that I’m abusing Swing and basically making Matlab work in unnatural ways, “something it was never meant to be“. I feel that using HTML as I’ve shown last week and in this post would fall under the same category in his eyes. To him and to others who complain I say that I have absolutely no remorse about doing this. When I purchase anything I have the full rights (within the scope of the license) to adapt it in whatever way fits my needs. As a software developer and manager for over 25 years, I’ve developed in dozens of programming languages and environments, and I still enjoy [ab]using Matlab. Matlab is a great environment to get things done quickly and if this sometimes requires a bit of HTML or Java hacks that make some people cringe, then that’s their problem, not mine – I’m content with being able to do in Matlab [nearly] everything I want, quickly, and move on to the next project. As long as it gets the job done, that’s fine by me. If this makes me more of an engineer than a computer scientist, then so be it.

On the flip side, I say to those who claim that Matlab is lacking in this or that aspect, that in most likelihood the limitation is only in their minds, not in Matlab – we can do amazing stuff with Matlab if we just open our minds, and possibly use some undocumented hacks. I’m not saying that Matlab has no limitations, I’m just saying that in most cases they can be overcome if we took the time and trouble to look for a solution. Matlab is a great tool and yet many people are not aware of its potential. Blaming Matlab for its failings is just an easy excuse in many cases. Of course, MathWorks could help my crusade on this subject by enabling useful features such as easy GUI component customizations…

On this sad day, I wish you all Shanah Tova!

]]>
https://undocumentedmatlab.com/blog_old/icon-images-in-matlab-uicontrols/feed 6
Aligning uicontrol contentshttps://undocumentedmatlab.com/blog_old/aligning-uicontrol-contents https://undocumentedmatlab.com/blog_old/aligning-uicontrol-contents#comments Thu, 22 Sep 2016 13:10:18 +0000 https://undocumentedmatlab.com/?p=6663 Related posts:
  1. Spicing up Matlab uicontrol tooltips Matlab uicontrol tooltips can be spiced-up using HTML and CSS, including fonts, colors, tables and images...
  2. Rich-contents log panel Matlab listboxes and editboxes can be used to display rich-contents HTML-formatted strings, which is ideal for log panels. ...
  3. Multi-line uitable column headers Matlab uitables can present long column headers in multiple lines, for improved readability. ...
  4. Undocumented button highlighting Matlab button uicontrols can easily be highlighted by simply setting their Value property. ...
]]>
Matlab automatically aligns the text contents of uicontrols: button labels are centered, listbox contents are left-aligned, and table cells align depending on their contents (left-aligned for strings, centered for logical values, and right-aligned for numbers). Unfortunately, the control’s HorizontalAlignment property is generally ignored by uicontrols. So how can we force Matlab buttons (for example) to have right-aligned labels, or for listbox/table cells to be centered? Undocumented Matlab has the answer, yet again…

It turns out that there are at least two distinct ways to set uicontrol alignment, using HTML and using Java. Today I will only discuss the HTML variant.

The HTML method relies on the fact that Matlab uicontrols accept and process HTML strings. This was true ever since Matlab GUI started relying on Java Swing components (which inherently accept HTML labels) over a decade ago. This is expected to remain true even in Matlab’s upcoming web-based GUI system, since Matlab would need to consciously disable HTML in its web components, and I see no reason for MathWorks to do so. In short, HTML parsing of GUI control strings is here to stay for the foreseeable future.

% note: no need to close HTML tags, e.g. </font></html>
uicontrol('Style','list', 'Position',[10,10,70,70], 'String', ...
          {'<HTML><FONT color="red">Hello</Font></html>', 'world', ...
           '<html><font style="font-family:impact;color:green"><i>What a', ...
           '<Html><FONT color="blue" face="Comic Sans MS">nice day!'});

Listbox with HTML items

Listbox with HTML items

While HTML formatting is generally frowned-upon compared to the alternatives, it provides a very quick and easy way to format text labels in various different manners, including using a combination of font faces, sizes, colors and other aspects (bold, italic, super/sub-script, underline etc.) within a single text label. This is naturally impossible to do with Matlab’s standard properties, but is super-easy with HTML placed in the label’s String property.

Unfortunately, while Java Swing (and therefore Matlab) honors only a [large] sub-set of HTML and CSS. The most important directives are parsed but some others are not, and this is often difficult to debug. Luckily, using HTML and CSS there are often multiple ways to achieve the same visual effect, so if one method fails we can usually find an alternative. Such was the case when a reader asked me why the following seemingly-simple HTML snippet failed to right-align his button label:

hButton.String = '<html><div style="text-align:right">text';

As I explained in my answer, it’s not Matlab that ignores the CSS align directive but rather the underlying Swing behavior, which snugly fits the text in the center of the button, and of course aligning text within a tight-fitting box has no effect. The workaround that I suggested simply forces Swing to use a non-tightly-fitting boundary box, within which we can indeed align the text:

pxPos = getpixelposition(hButton);
hButton.String = ['<html><div width="' num2str(pxPos(3)-20) 'px" align="right">text'];  % button margins use 20px

centered (default) button label   right-aligned button label

Centered (default) and right-aligned button labels

This solution is very easy to set up and maintain, and requires no special knowledge other than a bit of HTML/CSS, which most programmers know in this day and age.

Of course, the solution relies on the actual button size. So, if the button is created with normalized units and changes its size when its parent container is resized, we’d need to set a callback function on the parent (e.g., SizeChangedFcn of a uipanel) to automatically adjust the button’s string based on its updated size. A better solution that would be independent of the button’s pixel-size and would work even when the button is resized needs to use Java.

A related solution for table cells uses a different HTML-based trick: this time, we embed an HTML table cell within the Matlab control’s cell, employing the fact that HTML table cells can easily be aligned. We just need to ensure that the HTML cell is defined to be larger than the actual cell width, so that the alignment fits well. We do this by setting the HTML cell width to 9999 pixels (note that the tr and td HTML tags are necessary, but the table tag is optional):

uitable('Units','norm','Pos',[0,0,0.3,0.3], 'Data', ...
        {'Left', ...
         '<html><tr><td align=center width=9999>Center', ...
         '<html><tr><td align=right  width=9999>Right'});

Non-default alignment of uitable cells

Non-default alignment of uitable cells

As noted above, a better solution might be to set the underlying Java component’s alignment properties (or in the case of the uitable, its underlying JTable component’s cellrenderer’s alignment). But in the general case, simple HTML such as above could well be sufficient.

]]>
https://undocumentedmatlab.com/blog_old/aligning-uicontrol-contents/feed 6
Listbox selection hackshttps://undocumentedmatlab.com/blog_old/listbox-selection-hacks https://undocumentedmatlab.com/blog_old/listbox-selection-hacks#comments Wed, 13 Jul 2016 15:36:19 +0000 https://undocumentedmatlab.com/?p=6534 Related posts:
  1. Editbox data input validation Undocumented features of Matlab editbox uicontrols enable immediate user-input data validation...
  2. Continuous slider callback Matlab slider uicontrols do not enable a continuous-motion callback by default. This article explains how this can be achieved using undocumented features....
  3. 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....
  4. Customizing combobox popups Matlab combobox (dropdown) popups can be customized in a variety of ways. ...
]]>
Last week a reader on the CSSM newsgroup asked whether it is possible to programmatically deselect all listbox items. By default, Matlab listboxes enable a single item selection: trying to deselect it interactively has no effect, while trying to set the listbox’s Value property to empty ([]) results in the listbox disappearing and a warning issued to the Matlab console:

Single-selection Matlab listbox

>> hListbox = uicontrol('Style','list', 'String',{'item #1','item #2','item #3','item #4','item #5','item #6'});
>> set(hListbox,'Value',[]);
Warning: Single-selection 'listbox' control requires a scalar Value.
Control will not be rendered until all of its parameter values are valid
(Type "warning off MATLAB:hg:uicontrol:ValueMustBeScalar" to suppress this warning.)

The reader’s question was whether there is a way to bypass this limitation so that no listbox item will be selected. The answer to this question was provided by MathWorker Steve(n) Lord. Steve is a very long-time benefactor of the Matlab community with endless, tireless, and patient advise to queries small and large (way beyond the point that would have frustrated mere mortals). Steve pointed out that by default, Matlab listboxes only enable a single selection – not more and not less. However, when the listbox’s Max value is set to be >1, the listbox enables multiple-items selection, meaning that Value accepts and reports an array of item indices, and there is nothing that prevents this array from being empty (meaning no items selected):

>> hListbox = uicontrol('Style','list', 'Max',2, 'String',{'item #1','item #2','item #3','item #4','item #5','item #6'});
>> set(hListbox,'Value',[]);  % this is ok - listbox appears with no items selected

Note: actually, the listbox checks the value of MaxMin, but by default Min=0 and there is really no reason to modify this default value, just Max.

While this makes sense if you think about it, the existing documentation makes no mention of this fact:

The Max property value helps determine whether the user can select multiple items in the list box simultaneously. If Max – Min > 1, then the user can select multiple items simultaneously. Otherwise, the user cannot select multiple items simultaneously. If you set the Max and Min properties to allow multiple selections, then the Value property value can be a vector of indices.

Some readers might think that this feature is not really undocumented, since it does not directly conflict with the documentation text, but then so are many other undocumented aspects and features on this blog, which are not mentioned anywhere in the official documentation. I contend that if this feature is officially supported, then it deserves an explicit sentence in the official documentation.

However, the original CSSM reader wanted to preserve Matlab’s single-selection model while enabling deselection of an item. Basically, the reader wanted a selection model that enables 0 or 1 selections, but not 2 or more. This requires some tweaking using the listbox’s selection callback:

set(hListbox,'Callback',@myCallbackFunc);
 
...
function test(hListbox, eventData)
   value = get(hListbox, 'Value');
   if numel(value) > 1
       set(hListbox, 'Value', value(1));
   end
end

…or a callback-function version that is a bit better because it takes the previous selection into account and tries to set the new selection to the latest-selected item (this works in most cases, but not with shift-clicks as explained below):

function myCallbackFunc(hListbox, eventData)
   lastValue = getappdata(hListbox, 'lastValue');
   value = get(hListbox, 'Value');
   if ~isequal(value, lastValue)
      value2 = setdiff(value, lastValue);
      if isempty(value2)
         setappdata(hListbox, 'lastValue', value);
      else
         value = value2(1);  % see quirk below
         setappdata(hListbox, 'lastValue', value);
         set(hListbox, 'Value', value);
      end
   end
end

This does the job of enabling only a single selection at the same time as allowing the user to interactively deselect that item (by ctrl-clicking it).

There’s just a few quirks: If the user selects a block of items (using shift-click), then only the second-from-top item in the block is selected, rather than the expected last-selected item. This is due to line #9 in the callback code which selects the first value. Matlab does not provide us with information about which item was clicked, so this cannot be helped using pure Matlab. Another quirk that cannot easily be solved using pure Matlab is the flicker that occurs when the selection changes and is then corrected by the callback.

We can solve both of these problems using the listbox’s underlying Java component, which we can retrieve using my findjobj utility:

% No need for the standard Matlab callback now
set(hListbox,'Callback',[]);
 
% Get the underlying Java component peer
jScrollPane = findjobj(h);
jListbox = jScrollPane.getViewport.getView;
jListbox = handle(jListbox,'CallbackProperties');  % enable callbacks
 
% Attach our callback to the listbox's Java peer
jListbox.ValueChangedCallback = {@myCallbackFunc, hListbox};
 
...
function myCallbackFunc(jListbox, eventData, hListbox)
   if numel(jListbox.getSelectedIndices) > 1
      set(hListbox, 'Value', jListbox.getLeadSelectionIndex+1);  % +1 because Java indices start at 0
   end
end

We can use a similar mechanism to control other aspects of selection, for example to enable only up to 3 selections but no more etc.

We can use this underlying Java component peer for a few other useful selection-related hacks: First, we can use the peer’s RightSelectionEnabled property or setRightSelectionEnabled() method to enable the user to select by right-clicking listbox items (this is disabled by default):

jListbox.setRightSelectionEnabled(true);  % false by default
set(jListbox,'RightSelectionEnabled',true);  % equivalent alternative

A similarly useful property is DragSelectionEnabled (or the corresponding setDragSelectionEnabled() method), which is true by default, and controls whether the selection is extended to other items when the mouse drags an item up or down the listbox.

Finally, we can control whether in multi-selection mode we enable the user to only select a single contiguous block of items, or not (which is Matlab’s default behavior). This is set via the SelectionMode property (or associated setSelectionMode() method), as follows:

jListbox.setSelectionMode(javax.swing.ListSelectionModel.SINGLE_INTERVAL_SELECTION);
jListbox.setSelectionMode(1);  % equivalent alternative (less maintainable/readable, but simpler)

SINGLE_SELECTION (default for Max=1)SINGLE_INTERVAL_SELECTION (only possible with Java)MULTIPLE_INTERVAL_SELECTION (default for Max>1)
SINGLE_SELECTION =0SINGLE_INTERVAL_SELECTION =1MULTIPLE_INTERVAL_SELECTION =2
(Matlab default for Max=1)(only possible with Java)(Matlab default for Max>1)

Additional listbox customizations can be found in related posts on this blog (see links below), or in section 6.6 of my Matlab-Java Programming Secrets book (which is still selling nicely almost five years after its publication, to the pleasant surprise of my publisher…).

]]>
https://undocumentedmatlab.com/blog_old/listbox-selection-hacks/feed 4
Smart listbox & editbox scrollbarshttps://undocumentedmatlab.com/blog_old/smart-listbox-editbox-scrollbars https://undocumentedmatlab.com/blog_old/smart-listbox-editbox-scrollbars#comments Wed, 20 Apr 2016 17:47:46 +0000 https://undocumentedmatlab.com/?p=6379 Related posts:
  1. FindJObj GUI – display container hierarchy The FindJObj utility can be used to present a GUI that displays a Matlab container's internal Java components, properties and callbacks....
  2. Editbox data input validation Undocumented features of Matlab editbox uicontrols enable immediate user-input data validation...
  3. Customizing combobox popups Matlab combobox (dropdown) popups can be customized in a variety of ways. ...
  4. Customizing editboxes Matlab's editbox can be customized in many useful manners...
]]>
A good friend recently asked me for examples where using Java in Matlab programs provides a significant benefit that would offset the risk of using undocumented/unsupported functionality, which may possibly stop working in some future Matlab release. Today I will discuss a very easy Java-based hack that in my opinion improves the appearance of Matlab GUIs with minimal risk of a catastrophic failure in a future release.

The problem with Matlab listbox and multi-line editbox controls in the current (non web-based) GUI, is that they use a scrollbar whose behavior policy is set to VERTICAL_SCROLLBAR_ALWAYS. This causes the vertical scrollbar to appear even when the listbox does not really require it. In many cases, when the listbox is too narrow, this also causes the automatic appearance of a horizontal scrollbar. The end result is a listbox that displays 2 useless scrollbars, that possibly hide some listbox contents, and are a sore to the eyes:

Standard (left) and smart (right) listbox scrollbars

Standard (left) and smart (right) listbox scrollbars

   
default scrollbars (VERTICAL_SCROLLBAR_ALWAYS)

default scrollbars (VERTICAL_SCROLLBAR_ALWAYS)

non-default scrollbars (VERTICAL_SCROLLBAR_AS_NEEDED)     non-default scrollbars (VERTICAL_SCROLLBAR_AS_NEEDED)

non-default scrollbars (VERTICAL_SCROLLBAR_AS_NEEDED)

By default, Matlab implements a vertical scrollbar policy of VERTICAL_SCROLLBAR_ALWAYS for sufficiently tall uicontrols (>20-25 pixels, which practically means always) and VERTICAL_SCROLLBAR_NEVER for shorter uicontrols (this may possibly be platform-dependent).

A similar problem happens with the horizontal scrollbar: Matlab implements a horizontal scrollbar policy of HORIZONTAL_SCROLLBAR_NEVER for all editboxes and also for narrow listboxes (<35 pixels), and HORIZONTAL_SCROLLBAR_AS_NEEDED for wide listboxes.

In many cases we may wish to modify the settings, as in the example shown above. The solution to this is very easy, as I explained back in 2010.

All we need to do is to retrieve the control’s underlying Java reference (a Java JScrollPane object) and change the policy value to VERTICAL_SCROLLBAR_AS_NEEDED:

% Create a multi-line (Max>1) editbox uicontrol
hEditbox = uicontrol('style','edit', 'max',5, ...);
 
try  % graceful-degradation for future compatibility
   % Get the Java scroll-pane container reference
   jScrollPane = findjobj(hEditbox);
 
   % Modify the scroll-pane's scrollbar policies
   % (note the equivalent alternative methods used below)
   set(jScrollPane,'VerticalScrollBarPolicy',javax.swing.ScrollPaneConstants.VERTICAL_SCROLLBAR_AS_NEEDED);   %VERTICAL_SCROLLBAR_AS_NEEDED=20
   jScrollPane.setHorizontalScrollBarPolicy(javax.swing.ScrollPaneConstants.HORIZONTAL_SCROLLBAR_AS_NEEDED);  %HORIZONTAL_SCROLLBAR_AS_NEEDED=30
catch
   % Never mind...
end

Note that updating the uicontrol handle Position property has the side-effect of automatically reverting the scrollbar policies to their default values (HORIZONTAL_SCROLLBAR_NEVER and VERTICAL_SCROLLBAR_ALWAYS/NEVER). This also happens whenever the uicontrol is resized interactively (by resizing its container figure window, for example). It is therefore advisable to set jScrollPane’s ComponentResizedCallback property to “unrevert” the policies:

cbFunc = @(h,e) set(h,'VerticalScrollBarPolicy',20, 'HorizontalScrollBarPolicy',30);
hjScrollPane = handle(jScrollPane,'CallbackProperties');
set(hjScrollPane,'ComponentResizedCallback',cbFunc);

smart_scrollbars utility

I created a new utility called smart_scrollbars that implements all of this, which you can download from the Matlab File Exchange. The usage in Matlab code is very simple:

% Fix scrollbars for a specific listbox
hListbox = uicontrol('style','list', ...);
smart_scrollbars(hListbox)
 
% Fix scrollbars for a specific editbox
hEditbox = uicontrol('style','edit', 'max',5, ...);
smart_scrollbars(hEditbox)
 
% Fix all listbox/editbox scrollbars in a panel or figure
smart_scrollbars              % fixes all scrollbars in current figure (gcf)
smart_scrollbars(hFig)        % fixes all scrollbars in a specific figure
smart_scrollbars(hContainer)  % fixes all scrollbars in a container (panel/tab/...)

Performance considerations

Finding the underlying JScrollPane reference of Matlab listboxes/editboxes can take some time. While the latest version of findjobj significantly improved the performance of this, it can still take quite a while in complex GUIs. For this reason, it is highly advisable to limit the search to a Java container of the control that includes as few internal components as possible.

In R2014b or newer, this is easily achieved by wrapping the listbox/editbox control in a tightly-fitting invisible uipanel. The reason is that in R2014b, uipanels have finally become full-fledged Java components (which they weren’t until then), but more to the point they now contain a property with a direct reference to the underlying JPanel. By using this panel reference we limit findjobj‘s search only to the contained scrollpane, and this is much faster:

% Slower code:
hListbox = uicontrol('style','list', 'parent',hParent, 'pos',...);
smart_scrollbars(hListbox)
 
% Much faster (using a tightly-fitting transparent uipanel wrapper):
hPanel = uipanel('BorderType','none', 'parent',hParent, 'pos',...);  % same position/units/parent as above
hListbox = uicontrol('style','list', 'parent',hPanel, 'units','norm', 'pos',[0,0,1,1], ...);
smart_scrollbars(hListbox)

The smart_scrollbars utility detects cases where there is a potential for such speedups and reports it in a console warning message:

>> smart_scrollbars(hListbox)
Warning: smart_scrollbars can be much faster if the list/edit control is wrapped in a tightly-fitting uipanel (details)

If you wish, you can suppress this warning using code such as the following:

oldWarn = warning('off', 'YMA:smart_scrollbars:uipanel');
smart_scrollbars(hListbox)
warning(oldWarn);  % restore warnings

Musings on future compatibility

Going back to my friend’s question at the top of today’s post, the risk of future compatibility was highlighted in the recent release of Matlab R2016a, which introduced web-based uifigures and controls, for which the vast majority of Java hacks that I presented in this blog since 2009 (including today’s hack) will not work. While the full transition from Java-based to web-based GUIs is not expected anytime soon, this recent addition highlighted the risk inherent in using unsupported functionality.

Users can take a case-by-case decision whether any improved functionality or appearance using Java hacks is worth the extra risk: On one hand, such hacks have been quite stable and worked remarkably well for the past decade, and will probably continue working into 2020 or so (or longer if you keep using a not up-to-the-moment Matlab release, or if you create compiled applications). On the other hand, once they stop working sometime in R2020a (or whenever), major code rewrites may possibly be required, depending on the amount of dependency of your code on these hacks.

There is an obvious tradeoff between improved GUIs now and for the coming years, versus increased maintainability cost a few years in the future. Each specific GUI will have its own sweet spot on the wide spectrum between using no such hacks at all, through non-critical hacks that provide graceful functionality degradation if they ever fail, to major Java-based functionality that would require complete rework. It is certainly NOT an all-or-nothing decision. Users who take the conservative approach of using no unsupported feature at all, lose the opportunity to have professional grade Matlab GUIs today and in the upcoming years. Decisions, decisions, …

In any case, we can reduce the risk of using such hacks today by carefully wrapping all their code in try-catch blocks. This way, even if the code fails in some future Matlab release, we’d still be left with a working implementation based on fully-supported functionality. This is the reason why I’ve used such a block in the code snippet above, as well as in my smart_scrollbars utility. What this means is that you can safely use smart_scrollbars in your code today and if the worst happens and it stops working in a few years, then it will simply do nothing without causing any error. In other word, future compatibility in the form of graceful degradation. I strongly advise using such defensive coding techniques whenever you use unsupported features.

]]>
https://undocumentedmatlab.com/blog_old/smart-listbox-editbox-scrollbars/feed 6
Faster findjobjhttps://undocumentedmatlab.com/blog_old/faster-findjobj https://undocumentedmatlab.com/blog_old/faster-findjobj#comments Mon, 11 Apr 2016 09:18:14 +0000 https://undocumentedmatlab.com/?p=6376 Related posts:
  1. FindJObj – find a Matlab component’s underlying Java object The FindJObj utility can be used to access and display the internal components of Matlab controls and containers. This article explains its uses and inner mechanism....
  2. FindJObj GUI – display container hierarchy The FindJObj utility can be used to present a GUI that displays a Matlab container's internal Java components, properties and callbacks....
  3. 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....
  4. Minimize/maximize figure window Matlab figure windows can easily be maximized, minimized and restored using a bit of undocumented magic powder...
]]>
My findjobj utility, created in 2007 and updated over the years, has received wide recognition and is employed by numerous Matlab programs, including a few dozen utilities in the Matlab File Exchange. I am quite proud of this utility and find it extremely useful for customizing Matlab controls in many ways that are impossible using standard Matlab properties. I have shown many examples of this in this blog over the past years.

I am happy to announce that I have just uploaded a new version of findjobj to the Matlab File Exchange, which significantly improves the utility’s performance for the most common use-case of a single input and a single output, namely finding the handle of the underlying Java component (peer) of a certain Matlab control:

>> hButton = uicontrol('String','click me!');
 
>> tic, jButton = findjobj(hButton); toc  % old findjobj
Elapsed time is 1.513217 seconds.
 
>> tic, jButton = findjobj(hButton); toc  % new findjobj
Elapsed time is 0.029348 seconds.

The new findjobj is backward-compatible with the old findjobj and with all prior Matlab releases. It is a drop-in replacement that will significantly improve your program’s speed.

The new version relies on several techniques:

First, as I showed last year, in HG2 (R2014 onward), Matlab uipanels have finally become full-featured Java JPanels, that can be accessed and customized in many interesting manners. More to the point here, we can now directly access the underlying JPanel component handle using the uipanel‘s hidden JavaFrame property (thanks to MathWorks for supplying this useful hook!). The new findjobj version detects this and immediately returns this handle if the user specified a uipanel input.

I still do not know of any direct way to retrieve the underlying Java component’s handle for Matlab uicontrols, this has been a major frustration of mine for quite a few years. So, we need to find the containing Java container in which we will recursively search for the control’s underlying Java handle. In the old version of finjobj, we retrieve the containing figure’s JFrame reference and from it the ContentPane handle, and use this handle as the Java container that is recursively searched. This is quite slow when the figure window is heavily-laden with multiple controls. In the new version, we try to use the specified Matlab uicontrol‘s direct parent, which is very often a uipanel. In this case, we can directly retrieve the panel’s JPanel reference as explained above. This results in a must smaller and faster search since we need to recursively search far fewer controls within the container, compared to the figure’s ContentPane.

In addition, I used a suggestion by blog reader Hannes for a faster recursive search that uses the control’s tooltip rather than its size, position and class. Finally, the search order is reversed to search backward from the last child component, since this is the component that will most often contain the requested control peer.

Feel free to download and use the new findjobj version. The code for the fast variant can be found in lines #190-205 and #3375-3415.

Enjoy!

p.s. – as I explained last week, today’s discussion, and in general anything that has to do with Java peers of GUI controls, only relates to the existing JFrame-based figure windows, not to the new web-based uifigure.

]]>
https://undocumentedmatlab.com/blog_old/faster-findjobj/feed 11
Adding dynamic properties to graphic handleshttps://undocumentedmatlab.com/blog_old/adding-dynamic-properties-to-graphic-handles https://undocumentedmatlab.com/blog_old/adding-dynamic-properties-to-graphic-handles#comments Wed, 16 Sep 2015 17:26:44 +0000 https://undocumentedmatlab.com/?p=6006 Related posts:
  1. New information on HG2 More information on Matlab's new HG2 object-oriented handle-graphics system...
  2. Performance: accessing handle properties Handle object property access (get/set) performance can be significantly improved using dot-notation. ...
  3. 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....
  4. Matlab’s HG2 mechanism HG2 is presumably the next generation of Matlab graphics. This article tries to explore its features....
]]>
A client recently asked me to extend one of Matlab’s built-in graphic containers (uiflowcontainer in this specific case) with automatic scrollbars that would enable the container to act as a scroll-panel. The basic idea would be to dynamically monitor the container’s contents and when it is determined that they overflow the container’s boundaries, then attach horizontal/vertical scrollbars to enable scrolling the contents into view:

Scrollable Matlab container

Scrollable Matlab container

This may sound simple, but there are actually quite a few undocumented hacks that make this possible, including listening to ObjectChildAdded/ObjectChildRemoved events, location/size/visibility events, layout changes etc. Maybe I’ll blog about it in some future article.

Today’s post is focused on a specific aspect of this project, attaching dynamic properties to the builtin uiflowcontainer, that would enable users to modify the container’s properties directly, as well as control aspects of the scrolling using the new properties: handles to the parent container, as well as the horizontal and vertical scrollbars, and even a new refresh() method.

The “textbook” approach to this would naturally be to create a new class that extends (inherits) uiflowcontainer and includes these new properties and methods. Unfortunately, for some reason that escapes my understanding, MathWorks saw fit to make all of its end-use graphic object classes Sealed, such that they cannot be extended by users. I did ask for this to be changed long ago, but the powers that be apparently decided that it’s better this way.

So the fallback would be to create our own dedicated class having all the new properties as well as those of the original container, and ensure that all the property values are synchronized in both directions. This is probably achievable, if you have a spare few days and a masochistic state of mind. Being the lazy bum and authority-rebel that I am, I decided to take an alternate approach that would simply add my new properties to the built-in container handle. The secret lies in the undocumented function schema.prop (for HG1, R2014a and older) and the fully-documented addprop function (for HG2, R2014b and newer).

In the examples below I use a panel, but this mechanism works equally well on any Matlab HG object: axes, lines, uicontrols, figures, etc.

HG2 – addprop function

The addprop function is actually a public method of the dynamicprops class. Both the dynamicprops class as well as its addprop function are fully documented. What is NOT documented, as far as I could tell, is that all of Matlab’s builtin handle graphics objects indirectly inherit dynamicprops, via matlab.graphics.Graphics, which is a high-level superclass for all HG objects. The bottom line is that we can dynamically add run-time properties to any HG object, without affecting any other object. In other words, the new properties will only be added to the handles that we specifically request, and not to any others. This suits me just fine:

hProp = addprop(hPanel, 'hHorizontalScrollBar');
hPanel.hHorizontalScrollBar = hMyScrollbar;
hProp.SetAccess = 'private';  % make this property read-only

The new property hHorizontalScrollBar is now added to the hPanel handle, and can be accessed just like any other read-only property. For example:

>> get(hPanel, 'hHorizontalScrollBar')
ans = 
    JavaWrapper

>> hPanel.hHorizontalScrollBar
ans = 
    JavaWrapper

>> hPanel.hHorizontalScrollBar = 123
You cannot set the read-only property 'hHorizontalScrollBar' of UIFlowContainer.

Adding new methods is more tricky, since we do not have a corresponding addmethod function. The trick I used was to create a new property having the requested new method’s name, and set its read-only value to a handle of the requested function. For example:

hProp = addprop(hPanel, 'refresh');
hPanel.refresh = @myRefreshFunc;
hProp.SetAccess = 'private';  % make this property read-only

We can then invoke the new refresh “method” using the familiar dot-notation:

hPanel.refresh();

Note: if you ever need to modify the initial value in your code, you should revert the property’s SetAccess meta-property to 'public' before Matlab will enable you to modify the value:

try
    % This will raise an exception if the property already exists
    hProp = addprop(hPanel, propName);
catch
    % Property already exists - find it and set its access to public
    hProp = findprop(hPanel, propName);
    hProp.SetAccess = 'public';
end
hPanel.(propName) = newValue;

HG1 – schema.prop function

In HG1 (R2014a and earlier), we can use the undocumented schema.prop function to add a new property to any HG handle (which is a numeric value in HG1). Donn Shull wrote about schema.prop back in 2011, as part of his series of articles on UDD (Unified Data Dictionary, MCOS’s precursor). In fact, schema.prop is so useful that it has its own blog tag here and appears in no less than 15 separate articles (excluding today). With HG2’s debut 2 years ago, MathWorks tried very hard to rid the Matlab code corpus of all the legacy schema-based, replacing most major functionalities with MCOS-based HG2 code. But so far it has proven impossible to get rid of schema completely, and so schema code is still used extensively in Matlab to this day (R2015b). Search your Matlab path for “schema.prop” and see for yourself.

Anyway, the basic syntax is this:

hProp = schema.prop(hPanel, propName, 'mxArray');

The 'mxArray' specifies that the new property can accept any data type. We can limit the property to only accept certain types of data by specifying a less-generic data type, among those recognized by UDD (details).

Note that the meta-properties of the returned hProp are somewhat different from those of HG2’s hProp. Taking this into account, here is a unified function that adds/updates a new property (with optional initial value) to any HG1/HG2 object:

function addProp(hObject, propName, initialValue, isReadOnly)
    try
        hProp = addprop(hObject, propName);  % HG2
    catch
        try
            hProp = schema.prop(hObject, propName, 'mxArray');  % HG1
        catch
            hProp = findprop(hObject, propName);
        end
    end
    if nargin > 2
        try
            hProp.SetAccess = 'public';  % HG2
        catch
            hProp.AccessFlags.PublicSet = 'on';  % HG1
        end
        hObject.(propName) = initialValue;
    end
    if nargin > 3 && isReadOnly
        try
            % Set the property as read-only
            hProp.SetAccess = 'private';  % HG2
        catch
            hProp.AccessFlags.PublicSet = 'off';  % HG1
        end
    end
end
]]>
https://undocumentedmatlab.com/blog_old/adding-dynamic-properties-to-graphic-handles/feed 4
Customizing Matlab uipanelshttps://undocumentedmatlab.com/blog_old/customizing-matlab-uipanels https://undocumentedmatlab.com/blog_old/customizing-matlab-uipanels#comments Wed, 25 Feb 2015 12:24:50 +0000 https://undocumentedmatlab.com/?p=5595 Related posts:
  1. 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....
  2. 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...
  3. 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...
  4. Transparent Matlab figure window Matlab figure windows can be made fully or partially transparent/translucent or blurred - this article explains how...
]]>
The major innovation in Matlab release R2014b was the introduction of the new handle-based graphics system (HG2). However, this release also included a few other improvements to graphics/GUI that should not be overlooked. The most notable is that uitabs are finally officially documented/supported, following a decade or being undocumented (well, undocumented in the official sense, since I took the time to document this functionality in this blog and in my Matlab-Java book).

A less-visible improvement occurred with uipanels: Panels are very important containers when designing GUIs. They enable a visual grouping of related controls and introduce order to an otherwise complex GUI. Unfortunately, until R2014b panels were drawn at the canvas level, and did not use a standard Java Swing controls like other uicontrols. This made it impossible to customize uipanels in a similar manner to other GUI uicontrols (example).

In R2014b, uipanels have finally become standard Java Swing controls, a com.mathworks.hg.peer.ui.UIPanelPeer$UIPanelJPanel component that extends Swing’s standard javax.swing.JPanel and Matlab’s ubiquitous com.mathworks.mwswing.MJPanel. This means that we can finally customize it in various ways that are not available in plain Matlab.

We start the discussion with a simple Matlab code snippet. It is deliberately simple, since I wish to demonstrate only the panel aspects:

figure('Menubar','none', 'Color','w');
hPanel = uipanel('Title','Panel title', 'Units','norm', 'Pos',[.1,.1,.6,.7]);
hButton = uicontrol('String','Click!', 'Parent',hPanel);

Standard Matlab uipanel

Standard Matlab uipanel

Notice the default ‘etchedin’ panel border, which I hate (note the broken edges at the corners). Luckily, Swing includes a wide range of alternative borders that we can use. I’ve already demonstrated customizing Matlab uicontrols with Java borders back in 2010 (has it really been that long? wow!). In R2014b we can finally do something similar to uipanels:

The first step is to get the uipanel‘s underlying Java component’s reference. We can do this using my findjobj utility, but in the specific case of uipanel we are lucky to have a direct shortcut by using the panel’s undocumented hidden property JavaFrame and its PrintableComponent property:

>> jPanel = hPanel.JavaFrame.getPrintableComponent
jPanel =
com.mathworks.hg.peer.ui.UIPanelPeer$UIPanelJPanel[,0,0,97x74,...]

Let’s now take a look at the jPanel‘s border:

>> jPanel.getBorder
ans =
com.mathworks.hg.peer.ui.borders.TitledBorder@25cd9b97
 
>> jPanel.getBorder.get
                Border: [1x1 com.mathworks.hg.peer.ui.borders.EtchedBorderWithThickness]
          BorderOpaque: 0
                 Class: [1x1 java.lang.Class]
                 Title: 'Panel title'
            TitleColor: [1x1 java.awt.Color]
             TitleFont: [1x1 java.awt.Font]
    TitleJustification: 1
         TitlePosition: 2

Ok, simple enough. Let’s replace the border’s EtchedBorderWithThickness with something more appealing. We start with a simple red LineBorder having rounded corners and 1px width:

jColor = java.awt.Color.red;  % or: java.awt.Color(1,0,0)
jNewBorder = javax.swing.border.LineBorder(jColor, 1, true);  % red, 1px, rounded=true
jPanel.getBorder.setBorder(jNewBorder);
jPanel.repaint;  % redraw the modified panel

Rounded-corners LineBorder

Rounded-corners LineBorder

Or maybe a thicker non-rounded orange border:

jColor = java.awt.Color(1,0.5,0);
jNewBorder = javax.swing.border.LineBorder(jColor, 3, false);  % orange, 3px, rounded=false
jPanel.getBorder.setBorder(jNewBorder);
jPanel.repaint;  % redraw the modified panel

Another LineBorder example

Another LineBorder example

Or maybe a MatteBorder with colored insets:

jColor = java.awt.Color(0,0.3,0.8);  % light-blue
jNewBorder = javax.swing.border.MatteBorder(2,5,8,11,jColor)  % top,left,bottom,right, color
jPanel.getBorder.setBorder(jNewBorder);
jPanel.repaint;  % redraw the modified panel

MatteBorder with solid insets

MatteBorder with solid insets

MatteBorder can also use an icon (rather than a solid color) to fill the border insets. First, let’s load the icon. We can either load a file directly from disk, or use one of Matlab’s standard icons. Here are both of these alternatives:

% Alternative #1: load from disk file
icon = javax.swing.ImageIcon('C:\Yair\star.gif');
 
% Alternative #2: load a Matlab resource file
jarFile = fullfile(matlabroot,'/java/jar/mlwidgets.jar');
iconsFolder = '/com/mathworks/mlwidgets/graphics/resources/';
iconURI = ['jar:file:/' jarFile '!' iconsFolder 'favorite_hoverover.png'];  % 14x14 px
icon = javax.swing.ImageIcon(java.net.URL(iconURI));

We can now pass this icon reference to MatteBorder‘s constructor:

w = icon.getIconWidth;
h = icon.getIconHeight;
jNewBorder = javax.swing.border.MatteBorder(h,w,h,w,icon)  % top,left,bottom,right, icon
jPanel.getBorder.setBorder(jNewBorder);
jPanel.repaint;  % redraw the modified panel

MatteBorder with icon insets

MatteBorder with icon insets

Additional useful Swing borders can be found in the list of classes implementing the Border interface, or via the BorderFactory class. For example, let’s create a dashed border having a 3-2 ratio between the line lengths and the spacing:

jColor = java.awt.Color.blue;  % or: java.awt.Color(0,0,1);
lineWidth = 1;
relativeLineLength = 3;
relativeSpacing = 2;
isRounded = false;
jNewBorder = javax.swing.BorderFactory.createDashedBorder(jColor,lineWidth,relativeLineLength,relativeSpacing,isRounded);
jPanel.getBorder.setBorder(jNewBorder);
jPanel.repaint;  % redraw the modified panel

StrokeBorder (dashed)

StrokeBorder (dashed)

After seeing all these possibilities, I think you’ll agree with me that Matlab’s standard uipanel borders look pale in comparison.

Have you used any interesting borders in your Matlab GUI? Or have you customized your panels in some other nifty manner? If so, then please place a comment below.

]]>
https://undocumentedmatlab.com/blog_old/customizing-matlab-uipanels/feed 14
Unorthodox checkbox usagehttps://undocumentedmatlab.com/blog_old/unorthodox-checkbox-usage https://undocumentedmatlab.com/blog_old/unorthodox-checkbox-usage#comments Wed, 14 Jan 2015 21:41:18 +0000 https://undocumentedmatlab.com/?p=5457 Related posts:
  1. UISplitPane UISplitPane was recently chosen as Matlab Central's Pick of the Week. Here I detail its use of some undocumented Matlab features....
  2. 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....
  3. 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...
  4. JTattoo look-and-feel demo A demo GUI that shows the effects of using different look-and-feels, including the JTatoo library, is presented. ...
]]>
A few weeks ago, Robert Cumming explained how we can use a Matlab uicontrol’s CData property to provide an optical illusion of a transparent background. Today I will discuss another usage of this property, providing a simple checkbox control the unorthodox appearance of a split-pane divider.

The underlying problem description is easy: we wish to have the ability to split a Matlab uipanel into two or more sub-panels, separated by a draggable horizontal/vertical divider. Such split-panes are standard in any semi-decent GUI, but for some reason were never incorporated in official Matlab. This is a real pity, but not to worry as there are at least two alternatives we could use:

UISplitPane

UISplitPane is a utility that I wrote back in 2009 that uses a Java JSplitPane divider and associates it with plain Matlab panels on both sides. This solves the problem of embedding Matlab axes in Java panels, such as the ones provided by the standard Java JSplitPane. A detailed description of the technique can be found in my dedicated post on this utility.

Two levels of UISplitPane, with customized dividers

Two levels of UISplitPane, with customized dividers

[hDown,hUp,hDiv1] = uisplitpane(gcf, 'Orientation','ver', 'dividercolor',[0,1,0]);
[hLeft,hRight,hDiv2] = uisplitpane(hDown, 'dividercolor','r', 'dividerwidth',3);
t=0:.1:10; 
hax1=axes('Parent',hUp);    plot(t,sin(t));
hax2=axes('parent',hLeft);  plot(t,cos(t));
hax3=axes('parent',hRight); plot(t,tan(t));
hDiv1.DividerLocation = 0.75;    % one way to modify divider properties...
set(hDiv2,'DividerColor','red'); % ...and this is another way...

Making UISplitPane work in HG2 (R2014b onward) was quite a pain: numerous changes had to be made. For example, dynamic UDD properties can no longer be added to Matlab handles, only to Java ones. For Matlab handles, we now need to use the addprop function. For such properties, the UDD meta-property SetFunction is now called SetMethod (and similarly for Get) and only accepts function handles (not function handle cells as in UDD). Also, the UDD meta-property AccessFlags.PublicSet='off' needed to change to SetAccess='private'. Also, handle.listener no longer works; instead, we need to use the addlistener function. There are quite a few other similar tweaks, but UISplitPanenow hopefully works well on both old (HG1, R2014a and earlier) and new (HG2, R2014b+) Matlab releases. Let me know if you still see unhandled issues.

UIExtras flex-box

UIExtras (officially named “GUI Layout Toolbox”) is a toolbox of very useful GUI handling functions related to layout management. Written within MathWorks and originally posted in 2010, it has been under continuous maintenance ever since. While being called a “toolbox”, it is in fact freely-downloadable from the Matlab File Exchange.

The new HG2 introduced in R2014b did not just make code porting difficult for me – uiextras’ developers (MathWorkers Ben Tordoff and David Sampson) also encountered great difficulties in porting the code and making sure that it is backward compatible with HG1. In the end they gave up and we now have two distinct versions of the toolbox: the original version for HG1 (R2014a and earlier) and a new version for HG2 (R2014b+).

In my opinion, uiextras is one of the greatest examples of Matlab code on the File Exchange. It is well-written, well-documented and highly performant (although I would also have preferred it to be a bit more robust, it sometimes complains when used). Readers could benefit greatly by studying its techniques, and today’s subject topic is one such example. Specifically, the split-pane divider in uiextras (used by HBoxFlex and VBoxFlex) is simply a Matlab uicontrol having a custom CData property. This CData value is computed and set programmatically (at the bottom of uix.Divider) to display a flat color with some markings at the center (“hand-holds”, a visual cue for interactive dragging, which can be turned off if requested). Thus, for a vertical divider (for an HBoxFlex container) of height 100 pixels and width of 5 pixels, we would get a CData of 100x5x3 (x3 for RGB colors):

hHBox = uiextras.HBoxFlex('Spacing',6, 'BackgroundColor','b');  % Spacing=6 means divider width =6px, and CData width =5px
hLeft  = uicontrol('parent',hHBox, 'style','check', 'string','Left split pane');
hRight = uicontrol('parent',hHBox, 'style','radio', 'string','Right split pane');

UIExtras HBoxFlex with draggable split-pane divider

UIExtras HBoxFlex with draggable split-pane divider

The divider handle is a private property, so we cannot readily access it. However, as I have explained last year, we can use the builtin struct function:

oldWarn = warning('off','MATLAB:structOnObject');  % temporarily disable warning message on discouraged usage
hHBox_data = struct(hHBox);  % this includes hidden/private properties
warning(oldWarn);
hDividers = hHBox_data.Dividers;  % multiple dividers are possible in HBoxFlex/VBoxFlex
cdata = get(hDividers(1), 'CData');

A very nice trick here is that this divider uicontrol is not a pushbutton as we might have expected. Instead, it is a checkbox control. And while it does not look anything like a standard checkbox (due to the custom CData), checkboxes (and radio-buttons) have a very important advantage that caused them to be preferable over buttons: in buttons, there is always a small border showing at the control’s edges, but checkboxes do not have any 3D appearance, or in other words they do not have a border — their CData can span the entire extent of the control. Neat, right?

This enables us to customize the appearance of checkboxes (and radios) to any arbitrary shape, by setting the relevant CData pixels to transparent/bgcolor (as Robert showed last week for buttons). Matlab GUI controls no longer need to look a boring rectangle. We can have clickable stars, draggable icons, and other similar uses. This really opens up the possibilities for rich GUI appearance. If anyone uses this feature, please do post a comment below (preferably with a nice screenshot!).

]]>
https://undocumentedmatlab.com/blog_old/unorthodox-checkbox-usage/feed 1
Customizing combobox popupshttps://undocumentedmatlab.com/blog_old/customizing-combobox-popups https://undocumentedmatlab.com/blog_old/customizing-combobox-popups#comments Wed, 24 Sep 2014 12:01:07 +0000 https://undocumentedmatlab.com/?p=5056 Related posts:
  1. Editbox data input validation Undocumented features of Matlab editbox uicontrols enable immediate user-input data validation...
  2. FindJObj GUI – display container hierarchy The FindJObj utility can be used to present a GUI that displays a Matlab container's internal Java components, properties and callbacks....
  3. Tri-state checkbox Matlab checkboxes can easily be made to support tri-state functionality....
  4. Sliders in Matlab GUI Professional-looking slider controls can easily be integrated in Matlab GUI. ...
]]>
Last week I explained how we can use display custom items in a standard Matlab combobox (popup/dropdown), using its underlying Java component. Today I will show how we can use this Java component for other nice customizations of the combobox’s popup:

Underlying Java component

The first step is to find the underlying Java component of the Matlab combobox (aka popup) uicontrol. This is done using my findjobj utility:

% Create the Matlab combobox
items = {'<HTML><FONT color="red">Hello</Font></html>', 'world', ...
         '<html><font style="font-family:impact;color:green"><i>What a', ...
         '<Html><FONT color="blue" face="Comic Sans MS">nice day!</font>'};
hCombobox = uicontrol('Style','popup', 'Position',[10,100,120,20], 'String',items);
 
% Find the uicontrol's underlying Java component
jCombobox = findjobj(hCombobox);

For findjobj to work, the Matlab uicontrol needs to be visible – it will not have a Java component before it is rendered onscreen for the first time. If everything is successful, jCombobox should now be a reference to the underlying om.mathworks.hg.peer.ComboboxPeer$MLComboBox Java component, which is an extension of the standard Swing JComboBox, as can be seen using my checkClass utility:

>> jCombobox.checkClass
 
private com.mathworks.hg.peer.ComboboxPeer$MLComboBox (uiinspect)
 
Superclass: com.mathworks.mwswing.MJComboBox
Superclass: javax.swing.JComboBox
 
Methods in JComboBox missing in ComboboxPeer$MLComboBox:
   JComboBox()
   JComboBox(java.lang.Object[])
   JComboBox(java.util.Vector)
   JComboBox(javax.swing.ComboBoxModel)
 
Methods in ComboboxPeer$MLComboBox missing in JComboBox:
   ComboboxPeer$MLComboBox(com.mathworks.hg.peer.ComboboxPeer)
   isPopupWidthConstrained() : boolean
   isTipWhenTruncatedEnabled() : boolean
   processEvent(java.awt.AWTEvent)
   registerWithKeyBindingManager(com.mathworks.mwswing.binding.KeyBindingManager, java.lang.String)
   setConstrainPopupWidth(boolean)
   setEditorColumnCount(int)
   setTipWhenTruncatedEnabled(boolean)
 
Methods inherited & modified by ComboboxPeer$MLComboBox:
   getInsets() : java.awt.Insets
   setBackground(java.awt.Color)
   updateUI()
 
Interfaces in JComboBox missing in ComboboxPeer$MLComboBox:
   java.awt.ItemSelectable
   java.awt.event.ActionListener
   javax.accessibility.Accessible
   javax.swing.event.ListDataListener

We shall now use three properties of this object to customize the control’s popup:

MaximumRowCount

The MaximumRowCount numeric property (default=20) sets the maximal number of drop-down items to display in the visible portion of the popup, before requiring a scrollbar. This basically controls the popup’s height:

% Get the current MaximumRowCount value 
numItems = get(jCombobox, 'MaximumRowCount');
numItems = jCombobox.MaximumRowCount;     % equivalent - access the property directly
numItems = jCombobox.getMaximumRowCount;  % equivalent - use Java's accessor method (best way)
 
% Set the MaximumRowCount value
set(jCombobox,'MaximumRowCount',3);
jCombobox.MaximumRowCount = 3;      % equivalent - access the property directly
jCombobox.setMaximumRowCount(3);    % equivalent - use Java's accessor method (best way)

MaximumRowCount=20 (default)

MaximumRowCount=20
(default)

MaximumRowCount=3

MaximumRowCount=3
 

MaximumRowCount=2

MaximumRowCount=2
 

Note that MaximumRowCount is a Matlab extension to the standard Swing JComboBox, so if we use a JComboBox directly in our code (using javacomponent) we will not have this feature. Creating the ComboboxPeer$MLComboBox component instead is possible, but is beyond the scope of this article, because MathWorks chose for this class not to have JComboBox‘s standard constructors but rather only a constructor that accepts a com.mathworks.hg.peer.ComboboxPeer object.

PopupVisible

The PopupVisible property (default=false) is a boolean flag which controls whether the popup window is currently (or should be) displayed. If this property is updated, then the focus is automatically transferred to the popup window for easy item selection using the keyboard (up/down/enter keys). There are also equivalent convenience methods showPopup()/hidePopup():

% Is the popup currently shown?
isShown = get(jCombobox, 'PopupVisible');
isShown = jCombobox.PopupVisible;     % equivalent - access the property directly
isShown = jCombobox.isPopupVisible;   % equivalent - use Java's accessor method (best way)
 
% Display the popup
set(jCombobox,'PopupVisible',true);   % NOT 'on' - this is a Java property, not a Matlab HG one!
jCombobox.PopupVisible = true;        % equivalent - access the property directly
jCombobox.setPopupVisible(true);      % equivalent - use Java's accessor method (best way)
jCombobox.showPopup();                % equivalent - use Java's direct method
 
% Hide the popup
set(jCombobox,'PopupVisible',false);  % NOT 'off' - this is a Java property, not a Matlab HG one!
jCombobox.PopupVisible = false;       % equivalent - access the property directly
jCombobox.setPopupVisible(false);     % equivalent - use Java's accessor method (best way)
jCombobox.hidePopup();                % equivalent - use Java's direct method

Note that PopUpVisible is not a Matlab extension – it exists in the original Swing JComboBox. Unfortunately, it was not included in the list of properties that are exposed to the user by the high-level Matlab uicontrol, so we need to use the underlying Java component.

On a Windows platform the PopupVisible property is toggled, thereby showing/hiding the popup window, whenever the user clicks <Alt-Up> or <Alt-Down> when the combo-box has focus.

PopupWidthConstrained

The PopupWidthConstrained property (default=false) is a boolean flag which is another Matlab extension to the standard Swing JComboBox. It is apparently used to constrain the width of the drop-down list to the width of the text field. MathWorks took the trouble to add this feature because Swing JComboBox‘s width is constrained, causing a difficulty in distinguishing between popup values when the control is relatively narrow; Matlab’s MJComboBox‘s default unconstrained behavior is much more user-friendly:

PopupWidthConstrained=false (default)

PopupWidthConstrained=false
(default)

PopupWidthConstrained=true

PopupWidthConstrained=true
 

Note that the PopupWidthConstrained property’s read accessor methods is the expected isPopupWidthConstrained(), thereby also enabling the expected Matlab-standard format of get(‘PopupWidthConstrained’). However, the property update accessor method is not the expected setPopupWidthConstrained(flag) but rather a non-standard setConstrainPopupWidth(flag). For this reason, it is impossible to set this property using set(‘PopupWidthConstrained’,…), but only via the Java setConstrainPopupWidth() accessor method:

>> set(jCombobox,'PopupWidthConstrained',true)
??? Changing the 'PopupWidthConstrained' property of javahandle_withcallbacks.com.mathworks.hg.peer.ComboboxPeer$MLComboBox is not allowed.
 
>> jCombobox.setPopupWidthConstrained(true)
??? No appropriate method or public field setPopupWidthConstrained for class javahandle_withcallbacks.com.mathworks.hg.peer.ComboboxPeer$MLComboBox.
 
>> jCombobox.setConstrainPopupWidth(true)  % this is ok

For additional customizations of Matlab comboboxes, refer to section 6.7 of my Matlab-Java programming book.

R2014b

We’re all eagerly awaiting the much-anticipated R2014b release. As you all know, this is an important release with major functionality and engine improvements. It is therefore not surprising that the release date (which should normally have been September 1) is somewhat delayed. MathWorkers are hard at work fixing problems in the pre-release beta. This delay was actually anticipated, as can be seen from the pre-release expiry date.

We should all be patient and let MathWorks fix these issues without pressure. This release could be a real home-run and MathWorks should do all it can to ensure that it works as transparently and as backward-compatible as possible so that it indeed becomes a home run rather than an outfield foul ball. Let’s not have a repeat of R2010b, which required two separate service-pack updates. I urge MathWorks to take their time – better safe than sorry. I urge everyone else to be patient – it’s worth the wait.

When 14b is finally out, I will be here with a planned series of articles explaining how we can make good use of all its new goodies. Start drooling…

Happy Jewish New Year everybody!

]]>
https://undocumentedmatlab.com/blog_old/customizing-combobox-popups/feed 8
Customizing listbox/combobox itemshttps://undocumentedmatlab.com/blog_old/customizing-listbox-combobox-items https://undocumentedmatlab.com/blog_old/customizing-listbox-combobox-items#comments Wed, 17 Sep 2014 12:01:34 +0000 https://undocumentedmatlab.com/?p=5029 Related posts:
  1. UISplitPane UISplitPane was recently chosen as Matlab Central's Pick of the Week. Here I detail its use of some undocumented Matlab features....
  2. Additional uicontrol tooltip hacks Matlab's uicontrol tooltips have several limitations that can be overcome using the control's underlying Java object....
  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. 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...
]]>
Last week I wrote about using a variety of techniques to customize listbox items with an attached checkbox icon. Some of these methods used a standard Matlab listbox uicontrol, others used other controls. Today I wish to extend the discussion and show how Matlab listbox and combobox (pop-up) items can be customized in a variety of ways.

To add icons to listbox/combobox items, we could use standard HTML, as I’ve shown last week. This is the simplest method, requires no Java knowledge, and it usually works well. The problem is that when a listbox/combobox has numerous items (hundreds or more), it may start getting sluggish. In such case it is faster to use a dedicated Java cell-renderer that sets the icon, font, colors, tooltip and other aspects on an item-by-item basis. This runs faster and enables far greater customizability than what is possible with HTML. The drawback is that it requires some Java programming. No free lunch…

Listbox and combobox cell-renderers need to extend javax.swing.ListCellRenderer, similarly to uitable cell-renderers. This is basically a simple Java class that minimally contains just an empty constructor and a getListCellRendererComponent() method with a predefined signature. getListCellRendererComponent() is automatically called by the Swing render engine separately for each listbox item, and gets as input args a JList reference, the item value (typically a string), an integer list index, a boolean flag indicating whether the item is currently selected, and another flag indicating whether the item is currently in focus. getListCellRendererComponent() uses these parameters to customize and return a java.awt.Component, which is typically (but not necessarily) a standard Swing JLabel.

Here is a simple example that displays a folder of icon files in a Matlab listbox and combobox. Each item is the filename, with a customization that if the file is an icon, then this icon is displayed next to the file name, otherwise the name appears in red italic without an icon. For illustration, we’ll use Matlab’s builtin icons folder: %matlabroot%/toolbox/matlab/icons/:

Custom listbox cell-renderer    Custom combobox cell-renderer

Creating the cell renderer

We start by creating a custom ListCellRenderer. Place the following code in a file called LabelListBoxRenderer.java:

import java.awt.*;
import javax.swing.*;
import java.util.Hashtable;
 
public class LabelListBoxRenderer extends JLabel implements ListCellRenderer
{
    private String folderPath;
    private final Hashtable<String,ImageIcon> iconsCache = new Hashtable<String,ImageIcon>();
 
    // Class constructors
    public LabelListBoxRenderer() {
        setOpaque(true);
        setHorizontalAlignment(LEFT);
        setVerticalAlignment(CENTER);
    }
    public LabelListBoxRenderer(String folderPath) {
        this();
        this.folderPath = folderPath;
    }
 
    // Return a label displaying both text and image.
    public Component getListCellRendererComponent(
            JList list,
            Object value,
            int index,
            boolean isSelected,
            boolean cellHasFocus)
    {
        String label = value.toString();
        setFont(list.getFont());
        if (isSelected) {
            // Selected cell item
            setBackground(list.getSelectionBackground());
            setForeground(list.getSelectionForeground());
        } else {
            // Unselected cell item
            setBackground(list.getBackground());
            setForeground(list.getForeground());
        }
        try {
            String iconFname = (folderPath + "/" + label).replace('\\', '/');
            ImageIcon icon = getFileIcon(iconFname);
            setIcon(icon);
            if (icon.getIconWidth() > 0) {
                // Cell item is a valid icon filename
                list.setToolTipText(iconFname + " (" + icon.getIconWidth() + " x " + icon.getIconHeight() + ")");
            } else {
                // Cell item is not an icon filename
                list.setToolTipText(iconFname + " (not an icon)");
                setFont(getFont().deriveFont(Font.ITALIC));
                setForeground(Color.red);
            }
        } catch (Exception e) {
            list.setToolTipText(e.getMessage());
        }
        //System.out.println(index + ": " + label);  // debug console printout
        setText(label);
        return this;
    }
 
    // Modify the folder path (default = current folder)
    public void setFolderPath(String folderPath) {
        this.folderPath = folderPath;
    }
 
    // Lazily load the file icons only as needed, later reuse cached data
    private ImageIcon getFileIcon(String filename) {
        ImageIcon icon;
        if (iconsCache.containsKey(filename)) {
            // Reuse cached data
            icon = iconsCache.get(filename);
        } else {
            // Lazily load the file icons only as needed
            icon = new ImageIcon(filename);
            iconsCache.put(filename, icon);  // store in cache for later use
        }
        return icon;
    }
}

In the code above, I’ve cached the ImageIcons, so that the actual disk file is only accessed once rather than repeatedly whenever the cell needs to be rendered. For even improved performance, we could also cache the tooltips and derived italic font so that they would not be regenerated each time (note that the list’s font is not the same as the cell component’s font) – I will leave this as an exercise to the reader.

Next, compile this file (using the standard javac compiler or any Java IDE), ensuring that you target a JVM compatible with your Matlab (JVM 5 will work on R14SP2 onward, 6 on R2007b onward, and 7 only on R2013b or newer). For convenience, both the source and compiled files for the LabelListBoxRenderer class can be downloaded here: LabelListBoxRenderer.java, LabelListBoxRenderer.class.

Using the cell-renderer in Matlab listboxes

Now that we have a custom cell renderer, we should add the LabelListBoxRenderer.class file to Matlab’s Java classpath using the javaaddpath function and then use this class in Matlab:

% Create the Matlab listbox
iconsFolder = fullfile(matlabroot, 'toolbox/matlab/icons');
files = dir(iconsFolder);
hListbox = uicontrol('Style','list', 'String',{files.name}, 'Position',[10,10,120,150]);
 
% Find the uicontrol's underlying Java component
jScrollpane = findjobj(hListbox);
jListbox = jScrollpane.getViewport.getView;
 
% Update the listbox's cell-renderer
javaaddpath 'C:\Yair\Undocumented Matlab\Work\'   % location of my LabelListBoxRenderer.class
jRenderer = LabelListBoxRenderer(iconsFolder);
jListbox.setCellRenderer(jRenderer);
 
% Give the icons some space...
jListbox.setFixedCellHeight(18);

Custom listbox cell-renderer

Wasn’t too painful was it?

Using the cell-renderer in Matlab combo-boxes

Customizing Matlab combo-boxes is just as easy, and uses the same LabelListBoxRenderer class:

% Create the Matlab combobox
iconsFolder = fullfile(matlabroot, 'toolbox/matlab/icons');
files = dir(iconsFolder);
hCombobox = uicontrol('Style','popup', 'String',{files.name}, 'Position',[10,10,120,150]);
 
% Find the uicontrol's underlying Java component
jCombobox = findjobj(hCombobox);  % no scroll-pane for combos
 
% Update the combobox's cell-renderer
javaaddpath 'C:\Yair\Undocumented Matlab\Work\'   % location of my LabelListBoxRenderer.class
jRenderer = LabelListBoxRenderer(iconsFolder);
jCombobox.setRenderer(jRenderer);  % Note: not setCellRenderer()
 
% Give the icons some space...
jCombobox.setFixedCellHeight(18);
 
% Make the drop-down list shorter than the default (=20 items)
jCombobox.setMaximumRowCount(8);

Custom combobox cell-renderer

For additional aspects of listbox and combobox customizations, refer to sections 6.6 and 6.7 of my Matlab-Java programming book.

]]>
https://undocumentedmatlab.com/blog_old/customizing-listbox-combobox-items/feed 2
CheckboxListhttps://undocumentedmatlab.com/blog_old/checkboxlist https://undocumentedmatlab.com/blog_old/checkboxlist#comments Wed, 10 Sep 2014 18:00:55 +0000 https://undocumentedmatlab.com/?p=5012 Related posts:
  1. Tri-state checkbox Matlab checkboxes can easily be made to support tri-state functionality....
  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. Advanced JIDE Property Grids JIDE property grids can use complex cell renderer and editor components and can signal property change events asynchronously to Matlab callbacks...
  4. Color selection components Matlab has several internal color-selection components that can easily be integrated in Matlab GUI...
]]>
Several years ago I blogged about using a checkbox-tree in Matlab. A few days ago there was a question on the Matlab Answers forum asking whether something similar can be done with Matlab listboxes, i.e. add checkboxes next to each list item. There are actually several alternatives for this and I thought this could be a good opportunity to discuss them:

MathWorks CheckBoxList

MathWorks CheckBoxList


The HTML image variant

The simplest alternative is to use small icon images checked and unchecked as part of the listbox item labels. As I explained last year, listboxes (like all other Matlab uicontrols that rely on underlying Java Swing components), support HTML and can be formatted using HTML images. For example:

Matlab listbox with HTML image icons

Matlab listbox with HTML image icons

In order to check/uncheck items in the listbox, we can trap the underlying Java component’s MouseClickedCallback using the findjobj utility:

% Assume checked.gif, unchecked.gif are 16x16 icons
prefix = ['<html><img src="file:///' strrep(path_of_icon_files),'\','/') '/unchecked.gif" height=16 width=16 />'];
sampleData = strcat(prefix, {'first', 'Second', 'Third', 'and last'});  % all items are unchecked at first
hListbox = uicontrol(...);
jScrollPane = findjobj(hListbox);
jListbox = handle(jScrollPane.getViewport.getView, 'CallbackProperties');
jListbox.MouseClickedCallback = {@mouseClickedFcn,hListbox};
 
function mouseClickedFcn(jListbox, jEventData, hListbox)
   % Get the clicked item and row index
   clickedX = jEventData.getX;
   clickedY = jEventData.getY;
   if clickedX > 15,  return;  end  % did not click a checkbox so bail out
   clickedRow = jListbox.locationToIndex(java.awt.Point(clickedX,clickedY)) + 1;  % Matlab row index = Java row index+1
   if clickedRow <= 0,  return;  end  % clicked not on an item - bail out
   strs = get(hListbox,'String');
   clickedItem = strs{clickedRow};
 
   % Switch the icon between checked.gif <=> unchecked.gif
   if strfind(clickedItem,'unchecked')
       strs{clickedRow} = strrep(clickedItem,'unchecked','checked');
   else
       strs{clickedRow} = strrep(clickedItem,'checked','unchecked');
   end
   set(hListbox,'String',strs);  % update the list item
end

Finally, when we process the selected list item(s), we can simply check whether they contain ‘unchecked.gif’ or ‘checked.gif’. Pretty straight-forward stuff.

MathWorks CheckBoxList

com.mathworks.mwswing.checkboxlist.CheckBoxList is a JList extension that displays a list of labels in a list with a checkbox next to each label. The labels’ checkboxes can be set, unset and queried using methods supplied by the CheckBoxList class or its com.mathworks.mwswing.checkboxlist.DefaultListCheckModel model:

% First create the data model
jList = java.util.ArrayList;  % any java.util.List will be ok
jList.add(0,'First');
jList.add(1,'Second');
jList.add(2,'Third');
jList.add(3,'and last');
 
% Next prepare a CheckBoxList component within a scroll-pane
jCBList = com.mathworks.mwswing.checkboxlist.CheckBoxList(jList);
jScrollPane = com.mathworks.mwswing.MJScrollPane(jCBList);
 
% Now place this scroll-pane within a Matlab container (figure or panel)
[jhScroll,hContainer] = javacomponent(jScrollPane,[10,10,80,65],gcf);
 
% Update some items' state programmatically
jCBModel = jCBList.getCheckModel;
jCBModel.checkAll;
jCBModel.uncheckIndex(1);
jCBModel.uncheckIndex(3);
 
% Respond to checkbox update events
jhCBModel = handle(jCBModel, 'CallbackProperties');
set(jhCBModel, 'ValueChangedCallback', @myMatlabCallbackFcn);

This results in the following image:

MathWorks CheckBoxList

MathWorks CheckBoxList

We can query the various checked/unchecked states programmatically:

>> jCBList.getCheckedValues
ans =
[First, Third]
 
>> jCBList.getCheckedIndicies'
ans =
           0       2
 
>> jCBModel.isIndexChecked(0)
ans =
     1    % =true

JIDE’s CheckBoxList

There is also an unrelated JIDE equivalent: com.jidesoft.swing.CheckBoxList. Readers are referred to the JIDE documentation for additional details.

The basic idea is the same as with the MathWorks CheckBoxList: we create the data model, then create a CheckBoxList component within a JScrollPane and place this onscreen using the javacomponent function. We can then modify or query the data model programmatically, and set various callback functions to process user events.

% Prepare the data model as above
 
% Now display onscreen:
jCBList = com.jidesoft.swing.CheckBoxList(jList.toArray)
jScrollPane = com.mathworks.mwswing.MJScrollPane(jCBList);
[jhScroll,hContainer] = javacomponent(jScrollPane, [120,10,80,65], gcf);
 
% Do some programmatic updates:
jCBList.selectAll;  % reverse: jCBList.selectNone
jCBList.setCheckBoxListSelectedIndices([0,2]);

The appearance is very similar to the MathWorks CheckBoxList, except that JIDE’s CheckBoxList has slightly less space between the list rows, and between the checkboxes and labels. The main difference between these components is not in their visual appearance but rather in their supported functionalities (internal methods) – some people might prefer the MathWorks component, others might like JIDE better. To see these functionalities, use my uiinspect and/or checkClass utilities.

For additional information on the MathWorks and JIDE components, and how to investigate and customize them, see Chapter 5 of my Matlab-Java programming book.

ActiveX and other alternatives

If you are running on Windows, you could use ActiveX controls that implement checkbox list functionality. One such control that is pretty standard is Microsoft’s MSComctlLib.ListViewCtrl.2. I showed an example of ListViewCtrl usage a few years ago, and readers are referred there for details. Here is the end result:

Sorted ListViewCtrl

Sorted ListViewCtrl

Granted, this is more of a table having a checkbox column than a listbox, but you can easily make the ListViewCtrl have only a single column.

In addition to this standard ListViewCtrl control, there are plenty of other third-party ActiveX or Java controls that can more-or-less easily be integrated in our Matlab GUI. The drawback of ActiveX is that it only works on a limited set of platforms, whereas the Java-based components (either MathWorks or JIDE) work on all Matlab installations.

Matlab uitable in disguise

As a variant of the idea of using a table with a checkbox first column, we could use Matlab’s builtin uitable function, as suggested by Sebastian below. Here is a simple code snippet illustrating this idea:

data = {true,'First'; false,'Second'; true,'Third'; false,'and last'};
hTable = uitable('Data',data,'RowName',[],'ColumnName',[],'BackgroundColor',[1,1,1],'Position',[10,10,100,70],'ColumnWidth',{20,60});

Matlab uitable with checkbox column

Matlab uitable with checkbox column

Anyway, let no one say ever again that Matlab GUI is boring. It is not. It is only limited by our imagination and our willingness to find and customize components that implement our requirements. There are plenty of alternatives out there, we just need to reach out and use them. If you can’t do it yourself, you could always use an external consultant like me to help you.

]]>
https://undocumentedmatlab.com/blog_old/checkboxlist/feed 23
Undocumented button highlightinghttps://undocumentedmatlab.com/blog_old/undocumented-button-highlighting https://undocumentedmatlab.com/blog_old/undocumented-button-highlighting#respond Wed, 05 Feb 2014 16:00:48 +0000 https://undocumentedmatlab.com/?p=4635 Related posts:
  1. Spicing up Matlab uicontrol tooltips Matlab uicontrol tooltips can be spiced-up using HTML and CSS, including fonts, colors, tables and images...
  2. Rich-contents log panel Matlab listboxes and editboxes can be used to display rich-contents HTML-formatted strings, which is ideal for log panels. ...
  3. Aligning uicontrol contents Matlab uicontrols can often be customized using plain HTML/CSS, without need for advanced Java. ...
  4. Multi-line uitable column headers Matlab uitables can present long column headers in multiple lines, for improved readability. ...
]]>
One of my consulting clients approached me yesterday with a mystery: In his GUIDE-generated GUI, one of the buttons had a bluish tint, and no obvious property seemed to control this or to differentiate it from its sibling controls. Here’s a parred-down version of his GUI:

Highlighted GUI button

Highlighted GUI button

So while it was very nice to have a highlighted button in this manner, the fact that he did not know why it happened and how to control it was a bit unsettling. Which is where I came in, and it turns out that the solution to the mystery is simple and very easy to use. My client now happily switches button highlights on and off, just for the fun of it…

Before I describe the solution (spoiler alert: scroll down), I think it is instructional to understand the unsuccessful attempts, so here goes:

Various alternatives

Our first attempts to understand the situation were to modify the button control’s obvious suspect properties:

  • String – the button had an HTML label. One might presume that this caused the highlighting tint, perhaps an HTML image painted the background? HTML labels for uicontrols are really cool so it would be a pity to have to stop using them. Fortunately, replacing the HTML label with a simple string had no effect, so we can keep using HTML labels safely and freely. But we’re still left with our mystery, so moving on…
  • Border – yet another suspect: the control’s border and fly-over appearance feature affects its appearance. This also proved a dead-end: all the buttons had simple default borders, nothing special about the highlighted one.
  • Background – another dead end: while we could indeed set a non-standard button color, this property does not enable the tinting effect (lighter half at top, darker at bottom). Needless to say, in our case this property had the default (gray) value.
  • Selected – this property does not really highlight the control, but rather draws a thick dashed border around it (see below).
  • focus – by calling uicontrol(hButton) we can have Matlab set the focus on the button. The Operating System then automatically kicks in to add some shading effect. This finally looked close, but again, it was just not quite right.

Highlight (left); focus (center); Selected (right)

Highlight (left); focus (center); Selected (right)

Solution of the highlighting mystery

So maybe GUIDE attached some funky property value to the control? Let’s investigate. Remembering that the GUIDE-generated *.fig file is simply a standard MAT file with a different extension, we can load it into the Matlab workspace and dissect it. Drilling down the GUI hierarchy we find:

>> data = load('myGUI.fig', '-mat')
data = 
    hgS_070000: [1x1 struct]
 
>> d.hgS_070000.children(9).properties
ans = 
              Units: 'pixels'
           Callback: [function_handle]
           Position: [20 20 60 20]
             String: 'Yes'
              Value: 1    ApplicationData: [1x1 struct]
>> d.hgS_070000.children(10).properties
ans = 
              Units: 'pixels'
           Callback: [function_handle]
           Position: [100 20 60 20]
             String: 'No'
    ApplicationData: [1x1 struct]

When we compare the information that GUIDE stored for the two buttons we see that it stored an extra Value property for the ‘Yes’ button, and used the default HG value for the ‘No’ button. Let’s compare the property values in run-time (I’m using my objDiff utility for this):

>> hButton1 = findall(gcf, 'String', 'Yes');
>> hButton2 = findall(gcf, 'String', 'No');
>> props1 = get(hButton1);
>> props2 = get(hButton2);
>> objdiff(props1, props2)
ans = 
      Extent: {[0 0 24 19]  [0 0 17 19]}
    Position: {[20 20 60 20]  [100 20 60 20]}
      String: {'Yes'  'No'}
       Value: {[1]  [0]}

This pretty much nails it: pushbutton highlighting is controlled via the Value property. According to the official documentation, the Value property has no meaning for push-buttons, only for other uicontrol styles. This is obviously not so:

set(hButton, 'Value', 1);   % Turn button highlighting on
set(hButton, 'Value', 0);   % Turn button highlighting off (can use any value ~=1)

Under the hood

Under the hood, updating the Value property sets the pushbutton’s underlying Java control‘s Selected property to true. Note that the Java Selected property is entirely unrelated to Matlab’s Selected property (which has no underlying Java counterpart). I do not understand the design decision that let to this, but since it has been like this for many years I see little chance that it will be changed in the near future.

In any case, the Java Selected property indeed has a visual effect, but the actual effect depends on the current operating system and Look-&-Feel (LnF). You can play around with the LnF to achieve various other alternative highlighting effects, or customize one of your own.

Advanced Matlab GUI course – London 12-14 March, 2014

If this topic has piqued your interest, consider joining my Advanced Matlab GUI course in London on 12-14 March, 2014. In this course/seminar I will explore numerous other ways by which we can customize Matlab’s GUI and graphics in ways that you never knew were even possible! This is a unique opportunity to take your Matlab skills to a higher level within just a few days. This training is not offered anywhere else.

]]>
https://undocumentedmatlab.com/blog_old/undocumented-button-highlighting/feed 0
Listbox layout customizationhttps://undocumentedmatlab.com/blog_old/listbox-layout-customization https://undocumentedmatlab.com/blog_old/listbox-layout-customization#comments Wed, 13 Nov 2013 20:08:28 +0000 https://undocumentedmatlab.com/?p=4374 Related posts:
  1. Setting line position in an edit-box uicontrol Matlab uicontrols have many useful features that are only available via Java. Here's how to access them....
  2. Setting listbox mouse actions Matlab listbox uicontrol can be modified to detect mouse events for right-click context menus, dynamic tooltips etc....
  3. Customizing listbox & editbox scrollbars Matlab listbox and multi-line editbox uicontrols have pre-configured scrollbars. This article shows how they can be customized....
  4. Continuous slider callback Matlab slider uicontrols do not enable a continuous-motion callback by default. This article explains how this can be achieved using undocumented features....
]]>
I haven’t written on listboxes in a long while, and since I’ve recently posted on related controls (editbox, combo-box), I thought of following up with an article on customizing Matlab listbox layout. By the end of today’s article, you should be able to customize the layout of items within your listbox, such as the following:

Customized listbox layout   Customized listbox layout

Customized listbox layouts


For the following hacks, we need to gain access to the listbox control’s underlying Java component, which is a MathWorks class that extends the standard JList. We can get this component’s reference using the findjobj utility:

>> hListbox = uicontrol('Style','List', 'String',{'item #1','item #2'});
 
>> jScrollPane = java(findjobj(hListbox))
jScrollPane =
com.mathworks.hg.peer.utils.UIScrollPane[...]
 
>> jListbox = jScrollPane.getViewport.getView
jListbox =
com.mathworks.hg.peer.ListboxPeer$UicontrolList[...]

Like multi-line editboxes, listboxes are actually composed of a container (a com.mathworks.hg.peer.utils.UIScrollPane object) that includes three children, as expected from any JScrollPane: a javax.swing.JViewport that contains the ListboxPeer$UicontrolList component, and horizontal/vertical scrollbars. I explained how to customize the scrollbars in an article back in early 2010.

Today we are not interested in the scroll-pane or scollbars, but rather the jListbox component that takes up the view-port’s contents. This component includes many useful properties that we can access and modify, including several that control the layout of the list items:

LayoutOrientation sets the layout of listbox items within the viewport. Possible values include:

  • The default value (jListbox.VERTICAL=0) indicates the regular top-to-bottom arrangement
  • jListbox.VERTICAL_WRAP=1 sets a horizontal item layout, wrapping to a new row as necessary for the maximum number of rows determined by the VisibleRowCount property (default=8)
  • jListbox.HORIZONTAL_WRAP=2 sets a vertical item layout, wrapping to a new column at row number VisibleRowCount

For example:

jListbox.setLayoutOrientation(jListbox.HORIZONTAL_WRAP);
jListbox.setVisibleRowCount(3);
 
set(jListbox, 'LayoutOrientation',2, 'VisibleRowCount',3);  % equivalent alternative

LayoutOrientation = VERTICAL = 0
VisibleRowCount is irrelevant

LayoutOrientation = VERTICAL_WRAP = 1
VisibleRowCount = 3

LayoutOrientation = HORIZONTAL_WRAP = 2
VisibleRowCount = 3

FixedCellHeight and FixedCellWidth hold the listbox’s cells height (default=13 pixels) and width (default=-1). A value of -1 means that the actual size is determined by the default platform-dependent CellRenderer size:


FixedCellHeight = -1
FixedCellWidth = -1

FixedCellHeight = 10
FixedCellWidth = 30

FixedCellHeight = 16
FixedCellWidth = 50

We can use these properties to display a selection matrix of icons. For example, let’s display the icons in Matlab standard icons folder:

% Prepare the list of ImageIcon objects
iconsFolder = fullfile(matlabroot,'toolbox/matlab/icons');
imgs = dir(fullfile(iconsFolder,'*.gif'));
for iconIdx = 1 : length(imgs)
   iconFilename = fullfile(iconsFolder,imgs(iconIdx).name);
   iconFilename = strrep(iconFilename, '\', '/');
   htmlStr{iconIdx} = ['<html><img src="file:/' iconFilename '"/>'];  % no need for </html>
end
 
% Display in a standard one-column listbox
hListbox = uicontrol('style','list', 'string',htmlStr, 'position',[10,10,160,90]);
 
% Modify the listbox layout to display 18x18-pixel cells
jScrollPane = findjobj(hListbox);
jListbox = jScrollPane.getViewport.getView;
jListbox.setLayoutOrientation(jListbox.HORIZONTAL_WRAP)
jListbox.setVisibleRowCount(4)
jListbox.setFixedCellWidth(18)   % icon width=16  + 2px margin
jListbox.setFixedCellHeight(18)  % icon height=16 + 2px margin
jListbox.repaint  % refresh the display

Customized listbox layout

Customized listbox layout

Other interesting things that we can do with listboxes (among others):

  • Customize the scrollbars, as noted above
     
  • Display HTML-formatted list items:
    uicontrol('Style','list', 'Position',[10,10,70,70], 'String', ...
       {'<html><font color="red">Hello</font></html>', 'world', ...
        '<html><font style="font-family:impact;color:green"><i>What a', ...   % note: </i></font></html> are not needed
        '<html><font color="blue" face="Comic Sans MS">nice day!</font>'});   % note: </html> is not needed

    Listbox with HTML'ed items

    Listbox with HTML colored items

  • Setting dynamic tooltips and right-click context-menus:
    Listbox dynamic tooltip

    Listbox dynamic tooltip

       
    Listbox dynamic context (right-click) menu

    Listbox dynamic context (right-click) menu

Note that while the code above used the underlying Java component, absolutely no knowledge of Java is required to understand it or use it. In fact, the entire code above is pure Matlab, simply setting the component’s properties and calling its methods, and using its inherent support of HTML strings.

Much more advanced customizations are possible at the Java level, especially using a dedicated CellRenderer. Interested readers can find more information about these and other possible customizations in my report on “Advanced Customizations of Matlab Uicontrols“. This 90-page PDF report can be purchased here ($29, please allow 24 hours for delivery by email). The report explains how to customize Matlab’s uicontrols in ways that are simply not possible using documented Matlab properties. This includes treatment of push buttons, toggle buttons, radio buttons, checkboxes, editboxes, listboxes, popup menus (aka combo-boxes/drop-downs), sliders, labels, and tooltips. Much of the information in the report is also available in hard-copy format in chapter 6 of my Matlab-Java programming book.

If you’d like me to personally add similar magic to your GUI, email me to see if I can help.

Advanced listbox CellRenderer customization

Advanced listbox CellRenderer customization

Now tell the truth – doesn’t Matlab’s standard listbox look kinda boring after all this? :-)

]]>
https://undocumentedmatlab.com/blog_old/listbox-layout-customization/feed 14
Editable combo-boxhttps://undocumentedmatlab.com/blog_old/editable-combo-box https://undocumentedmatlab.com/blog_old/editable-combo-box#comments Wed, 09 Oct 2013 15:38:55 +0000 https://undocumentedmatlab.com/?p=4246 Related posts:
  1. 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...
  2. Adding a context-menu to a uitree uitree is an undocumented Matlab function, which does not easily enable setting a context-menu. Here's how to do it....
  3. 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...
  4. GUI integrated HTML panel Simple HTML can be presented in a Java component integrated in Matlab GUI, without requiring the heavy browser control....
]]>
In previous articles, I explained how we can use findjobj to customize a Matlab uicontrol’s underlying Java control, thereby improving its appearance and functionality. My two previous articles on the Matlab editbox were a classic example of this mechanism. Unfortunately, this technique does not always work well, and an alternative mechanism needs to be used. One such case in point is the subject of today’s article.

Matlab combo-box (a.k.a. “popup-menu” or “drop-down”) controls are very simple controls that accept a list of strings from which a user can select. This is a very simple control that answers a wide range of use-cases. Unfortunately, it is quite limited. Among other limitations, we cannot modify the popup-panel’s appearance/functionality; we cannot select multiple items; and we cannot type-in a value in the control’s editbox. Today’s article will focus on the latter limitation, namely how to use an editable combo-box.

Trying to make Matlab’s standard combobox editable

We can indeed use findjobj to get a Matlab combo-box’s underlying Java control. This turns out to be a com.mathworks.hg.peer.ComboboxPeer$MLComboBox object, which extends the standard Java Swing JComboBox:

>> hCombo = uicontrol('Style','popup', 'String',{'a','b','c'});
>> jCombo = findjobj(hCombo)
jCombo =
	javahandle_withcallbacks.com.mathworks.hg.peer.ComboboxPeer$MLComboBox

This jCombo control has the Editable property that we can then try to override (the default value is false):

>> jCombo.setEditable(true);
>> jCombo.Editable = true;          % equivalent alternative
>> set(jCombo,'setEditable',true);  % equivalent alternative
Editable combo-box control

Editable combo-box control

The bad news is that the moment we enter some value (as in the screenshot here) that is not already a member of the pop-up panel (i.e., the cell-array in the String property), then the control disappears and a warning message is issued to the Matlab console:

Warning: popupmenu control requires that Value be an integer within String range
Control will not be rendered until all of its parameter values are valid
(Type "warning off MATLAB:hg:uicontrol:ParameterValuesMustBeValid" to suppress this warning.)

The reason for this behavior is that when the combo-box object detects that the text field’s content match none of the popup list items, it automatically sets jCombo‘s SelectedIndex to -1 and Matlab’s corresponding HG Value property to 0. At this point the Matlab implementation kicks in, hiding the uicontrol since it considers 0 an invalid value for the Value property. This is similar to the check being done to test for an empty HG String value (=no items):

>> set(hCombo, 'string', [])
popupmenu control requires a non-empty String
Control will not be rendered until all of its parameter values are valid.

We can clear these particular warnings via:

warning('off','MATLAB:hg:uicontrol:ParameterValuesMustBeValid')

but this does not prevent the control from being hidden – it just prevents the warning from showing on the Command Window.

We can dive deeper and try to modify the underlying data model and disassociate the Java control from HG, but let’s stop at this point since there is really no point considering the fact that there is a much simpler alternative.

Note: if you do decide to make the standard Matlab uicontrol editable, read here for a related customization that I posted several years ago.

The pure-Java alternative

Rather than customizing Matlab’s uicontrol, we can easily create an identical-looking control using the standard Java Swing JComboBox, which has none of these problems/limitations. We can create and display the component in one go using the semi-documented javacomponent function:

position = [10,100,90,20];  % pixels
hContainer = gcf;  % can be any uipanel or figure handle
options = {'a','b','c'};
model = javax.swing.DefaultComboBoxModel(options);
jCombo = javacomponent('javax.swing.JComboBox', position, hContainer);jCombo.setModel(model);jCombo.setEditable(true);

We can use a variant of javacomponent to create the component with the model in one go, replacing the highlighted lines above:

jCombo = javacomponent({'javax.swing.JComboBox',model}, position, hContainer);

Once we have the control ready, all we need to do is set its ActionPerformedCallback property to our Matlab callback function and we’re pretty-much set. We can get the currently-selected text using char(jCombo.getSelectedItem) and the selected list index (0-based) using jCombo.getSelectedIndex (which returns -1 if we entered a non-listed value, 0 for the first list item, 1 for the second etc.). More information can be found here.

Lesson learnt

In the past 20+ years of my professional life as engineer and development manager, my number one rule has always been:

DON’T FIX IT, IF IT AIN’T BROKE!

But sometimes, we should also remember an alternative version:
DON’T FIX IT, IF IT’S EASIER TO REPLACE!

Available report – “Advanced Customizations of Matlab Uicontrols”

Interested readers can find more information about these and other possible customizations in my report on “Advanced Customizations of Matlab Uicontrols“. This 90-page PDF report can be purchased here ($29, please allow 24 hours for delivery by email). The report explains how to customize Matlab’s uicontrols in ways that are simply not possible using documented Matlab properties. This includes treatment of push buttons, toggle buttons, radio buttons, checkboxes, editboxes, listboxes, popup menus (aka combo-boxes/drop-downs), sliders, labels, and tooltips. Much of the information in the report is also available in hard-copy format in chapter 6 of my Matlab-Java programming book.

]]>
https://undocumentedmatlab.com/blog_old/editable-combo-box/feed 20
Editbox data input validationhttps://undocumentedmatlab.com/blog_old/editbox-data-input-validation https://undocumentedmatlab.com/blog_old/editbox-data-input-validation#comments Wed, 02 Oct 2013 14:00:51 +0000 https://undocumentedmatlab.com/?p=4229 Related posts:
  1. 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....
  2. FindJObj GUI – display container hierarchy The FindJObj utility can be used to present a GUI that displays a Matlab container's internal Java components, properties and callbacks....
  3. Continuous slider callback Matlab slider uicontrols do not enable a continuous-motion callback by default. This article explains how this can be achieved using undocumented features....
  4. 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....
]]>
Last week I explained how Matlab’s editbox control can be customized using its underlying Java component. Today I extend that article by explaining how we can use this information to provide a very user-friendly input-validation function for Matlab editboxes.

Zip-code entry validation example

Zip-code entry validation example


As before, we first need to get the Matlab control’s underlying Java control. This is done using the findjobj utility:

% Prepare the log editbox
hEditbox = uicontrol('Style','edit', 'String','Matlab', ...);
 
% Get the underlying Java editbox
jEditbox = findjobj(hLogPanel);
 
try
    % Multi-line editboxes are contained within a scroll-panel
    jEditbox = handle(jEditbox.getViewport.getView, 'CallbackProperties');
catch
    % probably a single-line editbox
end

Callbacks

Once we have the jEditbox reference handle, we can use some ~30 different event callbacks that it exposes. Some of the useful callbacks include:

  • ActionPerformedCallback – fired when <enter> is clicked in the editbox
  • CaretUpdateCallback – fired when the caret position has changed
  • KeyTypedCallback – fired whenever a keyboard button is typed when the editbox has focus

For example:

set(jEditbox, 'KeyPressedCallback',@myValidationFunction);
 
% Callback function definition
function myValidationFunction(jEditbox, eventData)
    % The following comments refer to the case of Alt-Shift-b
    keyChar = get(eventData,'KeyChar');  % or: eventData.getKeyChar  ==> 'B'
    isAltDown = get(eventData,'AltDown');  % ==> 'on'
    isAltDown = eventData.isAltDown;  % ==> true
    modifiers = get(eventData,'Modifiers');  % or: eventData.getModifiers ==> 9 = 1 (Shift) + 8 (Alt)
    modifiersDescription = char(eventData.getKeyModifiersText(modifiers));  % ==> 'Alt+Shift'
    % (now decide what to do with this key-press...)
end

Using such a validation function enables us to immediately convert typed characters into ‘*’ (in password fields) or check that the input conforms to a standard format such as a 5-digit zip code, a valid-looking email address or a valid-looking credit-card number (Luhn’s algorithm, recently featured in a video tutorial by Doug Hull). Of course, there are dedicated JIDE controls that do much of this already, but let’s not digress.

In today’s example, we shall implement a simple input-validation function for a 5-digit zip code. When the input data is invalid, the editbox will be colored red and an appropriate message will appear next to the editbox. In addition, invalid (non-digit) characters shall be rejected with a beep sound.

Zip-code validation example

To illustrate the above, let’s use an example of a 5-digit zip-code entry validation. We start by creating an empty editbox with an associated message label next to it:

figure('Color','w', 'Menubar','none');
hEditbox = uicontrol('Style','edit', 'Pos',[10,10,60,20], 'String','Matlab');  % start with an invalid string
hMessageLabel = uicontrol('Style','text', 'Pos',[80,10,200,20], 'horizontal','left', 'background','w', 'Foreground','red');

Next we get the underlying jEditbox reference and set its entry-validation callback function:

jEditbox = findjobj(hEditbox);  % single-line editbox so there's need to drill-down the scroll-pane
set(jEditbox, 'KeyPressedCallback',{@editboxValidation,hMessageLabel});

Note how we pass the message-label’s handle as an extra input parameter to the callback function.

Now we define the callback function editboxValidation and place it on the Matlab path (for example, by placing the following within editboxValidation.m in a folder that is already on your path):

% editboxValidation - ensure that an editbox input is a valid 5-digit zip code
function editboxValidation(jEditbox, eventData, hMessageLabel)
    keyChar = eventData.getKeyChar;  % see note below about how we can trick Matlab here
    if ~alldigits(keyChar) && isprintable(keyChar)
        beep;
        fixedText = strrep(char(jEditbox.getText), keyChar, '');
        jEditbox.setText(fixedText);
    end
    updateAppearance(jEditbox, hMessageLabel);
end
 
% Check whether a string only contains digits
function flag = alldigits(str)
    flag = ~isnan(str2double(str));
end
 
% Check whether a character is printable
function flag = isprintable(keyChar)
    keyVal = double(keyChar);
    flag = ~isempty(keyVal) && keyVal > 31 && keyVal < 128;
end
 
% Update the GUI appearance based on the editbox text
function updateAppearance(jEditbox, hMessageLabel)
    currentText = char(jEditbox.getText);
    if isempty(currentText)
        set(hMessageLabel, 'String','Please enter a 5-digit zip-code')
        jEditbox.setBorder(javax.swing.border.LineBorder(java.awt.Color.red, 3, false));
    elseif ~alldigits(currentText)
        beep;
        set(hMessageLabel, 'String','Invalid zip: should only contain digits')
        jEditbox.setBorder(javax.swing.border.LineBorder(java.awt.Color.red, 3, false));
    elseif length(currentText) ~= 5
        set(hMessageLabel, 'String','Invalid zip: should have exactly 5 digits')
        jEditbox.setBorder(javax.swing.border.LineBorder(java.awt.Color.red, 3, false));
    else
        set(hMessageLabel, 'String','');
        jEditbox.setBorder(javax.swing.border.LineBorder(java.awt.Color.gray, 1, false));
    end
end

Finally, we call the validation function directly after creating our GUI, to let the user know that the zip-code needs to be entered:

% Note how we trick Matlab by using eventData as a struct rather than a Java object
% (i.e., getKeyChar is set here to be a simple struct field, rather than a Java method)
eventData.getKeyChar = '';
editboxValidation(jEditbox,eventData,hMessageLabel)

Zip-code entry validation example

Zip-code entry validation example

Naturally, this is a very simple example, and you can easily expand it for your needs. But it does show the basic components of any input validation: checking the new data, updating the control as appropriate, and modifying the appearance of the underlying control and of other associated controls.

Available report – “Advanced Customizations of Matlab Uicontrols”

Interested readers can find more information about these and other possible customizations in my report on “Advanced Customizations of Matlab Uicontrols“. This 90-page PDF report can be purchased here ($29, please allow 24 hours for delivery by email). The report explains how to customize Matlab’s uicontrols in ways that are simply not possible using documented Matlab properties. This includes treatment of push buttons, toggle buttons, radio buttons, checkboxes, editboxes, listboxes, popup menus (aka combo-boxes/drop-downs), sliders, labels, and tooltips. Much of the information in the report is also available in hard-copy format in chapter 6 of my Matlab-Java programming book.

]]>
https://undocumentedmatlab.com/blog_old/editbox-data-input-validation/feed 6