Figure – 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 9 (popup figures)https://undocumentedmatlab.com/blog_old/matlab-toolstrip-part-9-popup-figures https://undocumentedmatlab.com/blog_old/matlab-toolstrip-part-9-popup-figures#comments Sun, 10 Feb 2019 17:00:10 +0000 https://undocumentedmatlab.com/?p=8402 Related posts:
  1. Builtin PopupPanel widget We can use a built-in Matlab popup-panel widget control to display lightweight popups that are attached to a figure window. ...
  2. Toolbar button labels GUI toolbar button labels can easily be set and customized using underlying Java components. ...
  3. Matlab toolstrip – part 2 (ToolGroup App) Matlab users can create custom Apps with toolstrips and docked figures. ...
  4. Frameless (undecorated) figure windows Matlab figure windows can be made undecorated (borderless, title-less). ...
]]>
In previous posts I showed how we can create custom Matlab app toolstrips using various controls. Today I will show how we can incorporate popup forms composed of Matlab figures into our Matlab toolstrip. These are similar in concept to drop-down and gallery selectors, in the sense that when we click the toolstrip button a custom popup is displayed. In the case of a popup form, this is a fully-customizable Matlab GUI figure.
Popup figure in Matlab toolstrip

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.

Also, remember to add the following code snippet at the beginning of your code so that the relevant toolstrip classes will be recognized by Matlab:

import matlab.ui.internal.toolstrip.*

Main steps and usage example

To attach a figure popup to a toolstrip control, follow these steps:

  1. Create a new figure, using GUIDE or the figure function. The figure should typically be created modal and non-visible, unless there’s a good reason to avoid this. Note that the figure needs to be a legacy (Java-based) figure, created with GUIDE or the figure function — web-based uifigure (created with AppDesigner or the uifigure function) is not [currently] supported.
  2. Create a callback function that opens and initializes this figure, and then moves it to the expected screen location using the following syntax: hToolGroup.showFigureDialog(hFig,hAnchor), where hFig is the figure’s handle, and hAnchor is the handle for the triggering toolstrip control.
  3. Attach the callback function to the triggering toolstrip control.

Here’s a simple usage example, in which I present a file-selector popup:

% Create a toolstrip section, column & push-button
hSection = hTab.addSection('Popup');
hColumn = hSection.addColumn();
hButton = Button('Open',Icon.OPEN_24);
hButton.ButtonPushedFcn = {@popupFigure,hButton};  % attach popup callback to the button
hColumn.add(hButton);
 
% Callback function invoked when the toolstrip button is clicked
function popupFigure(hAction, hEventData, hButton)
    % Create a new non-visible modal figure
    hFig = figure('MenuBar','none', 'ToolBar','none', 'WindowStyle','modal', ...
                  'Visible','off', 'NumberTitle','off', 'Name','Select file:');
 
    % Add interactive control(s) to the figure (in this case, a file chooser initialized to current folder)
    jFileChooser = handle(javaObjectEDT(javax.swing.JFileChooser(pwd)), 'CallbackProperties');
    [jhFileChooser, hComponent] = javacomponent(jFileChooser, [0,0,200,200], hFig);
    set(hComponent, 'Units','normalized', 'Position',[0,0,1,1]);  % resize component within containing figure
 
    % Set popup control's callback (in this case, display the selected file and close the popup)
    jhFileChooser.ActionPerformedCallback = @popupActionPerformedCallback;
    function popupActionPerformedCallback(jFileChooser, jEventData)
        fprintf('Selected file: %s\n', char(jFileChooser.getSelectedFile));
        delete(hFig);
    end
 
    % Display the popup figure onscreen, just beneath the triggering button
    showFigureDialog(hToolGroup,hFig,hButton);
 
    % Wait for the modal popup figure to close before resuming GUI interactivity
    waitfor(hFig);
end

This leads to the popup figure as shown in the screenshot above.

The popup figure initially appears directly beneath the triggering button. The figure can then be moved away from that position, by dragging its title bar or border frame.

Note how the popup is an independent heavy-weight figure window, having a border frame, title bar and a separate task-bar icon. Removing the border frame and title-bar of Matlab figures can be done using an undocumented visual illusion – this can make the popup less obtrusive, but also prevent its moving/resizing. An entirely different and probably better approach is to present a light-weight popup panel using the Toolpack framework, which I plan to discuss in the following post(s). The PopupPanel container that I discussed in another post cannot be used, because it is displayed as a sub-component of a Matlab figure, and in this case the popup is not attached to any figure (the toolstrip and ToolGroup are not Matlab figures, as explained here).

The astute reader may wonder why I bothered going to all the trouble of displaying a modal popup with a JFileChooser, when I could have simply used the built-in uigetfile or uiputfile functions in the button’s callback. The answer is that (a) this mechanism displays the popup directly beneath the triggering button using hToolGroup.showFigureDialog(), and also (b) enables complex popups (dialogs) that have no direct builtin Matlab function (for example, a file-selector with preview, or a multi-component input form).

Compatibility considerations for R2018a or older

In Matlab releases R2018a or older that do not have the hToolGroup.showFigureDialog() function, you can create it yourself in a separate showFigureDialog.m file, as follows:

function showFigureDialog(hToolGroup, hFig, hAnchor)
    %   showFigureDialog - Display a figure-based dialog below a toolstrip control.
    %
    %   Usage example:
    %       showFigureDialog(hToolGroup, hFig, hAnchor);
    %   where: 
    %       "hToolGroup" must be a "matlab.ui.internal.desktop.ToolGroup" handle
    %       "hFig" must be a "figure" handle, not a "uifigure"
    %       "hAnchor" must be a "matlab.ui.internal.toolstrip.***" handle
 
    %hWarn = ctrlMsgUtils.SuspendWarnings('MATLAB:HandleGraphics:ObsoletedProperty:JavaFrame'); %#ok<NASGU>
    hWarn = warning('off','MATLAB:HandleGraphics:ObsoletedProperty:JavaFrame');
    jf = get(hFig, 'JavaFrame');
    if isempty(jf)
        error('UI figure cannot be added to "ToolGroup". Use a regular figure instead.')
    else
        screen_size = get(0,'ScreenSize');
        old_pos = get(hFig,'OuterPosition');
        dpi_ratio = com.mathworks.util.ResolutionUtils.scaleSize(100)/100;
        jAnchor = hToolGroup.ToolstripSwingService.Registry.getWidgetById(hAnchor.getId());
        pt = javaMethodEDT('getLocationOnScreen',jAnchor); % pt is anchor top left
        pt.y = pt.y + jAnchor.getVisibleRect().height;     % pt is anchor bottom left
        new_x = pt.getX()/dpi_ratio-5;                           % figure outer left
        new_y = screen_size(end)-(pt.getY/dpi_ratio+old_pos(4)); % figure outer bottom
        hFig.OuterPosition = [new_x new_y old_pos(3) old_pos(4)];
        hFig.Visible = 'on';
    end
    warning(hWarn);
end

Under the hood of showFigureDialog()

How does showFigureDialog() know where to place the figure, directly beneath the triggering toolstrip anchor?

The answer is really quite simple, if you look at this method’s source-code in %matlabroot%/toolbox/matlab/toolstrip/+matlab/+ui/+internal/+desktop/ToolGroup.m (around line 500, depending on the Matlab release).

The function first checks whether the input hFig handle belongs to a figure or uifigure, and issues an error message in case it’s a uifigures (only legacy figures are currently supported).
Then the function fetches the toolstrip control’s underlying Java control handle using the following code (slightly modified for clarity), as explained here:

jAnchor = hToolGroup.ToolstripSwingService.Registry.getWidgetById(hAnchor.getId());

Next, it uses the Java control’s getLocationOnScreen() to get the control’s onscreen position, accounting for monitor DPI variation that affects the X location.
The figure’s OuterPosition property is then set so that the figure’s top-left corner is exactly next to the control’s bottom-left corner.
Finally, the figure’s Visible property is set to ‘on’ to make the figure visible in its new position.

The popup figure’s location is recomputed by showFigureDialog() whenever the toolstrip control is clicked, so the popup figure is presented in the expected position even when you move or resize the tool-group window.

Toolstrip miniseries roadmap

The following post(s) will present the Toolpack framework. Non-figure (lightweight) popup toolpack panels can be created, which appear more polished/stylish than the popup figures that I presented today. The drawdown is that toolpack panels may be somewhat more complex to program than figures, and IMHO are more likely to change across Matlab releases. In addition to the benefit of popup toolpack panels, toolpack presents an alternative way for toolstrip creation and customization, enabling programmers to choose between using the toolstrip framework (that I discussed so far), and the new toolpack framework.

In a succeeding post, I’ll discuss toolstrip collapsibility, i.e. what happens when the user resizes the window, reducing the toolstrip width. Certain toolstrip controls will drop their labels, and toolstrip sections shrink into a drop-down. The priority of control/section collapsibility can be controlled, so that less-important controls will collapse before more-important ones.

In future posts, I plan to discuss 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-9-popup-figures/feed 5
Matlab toolstrip – part 8 (galleries)https://undocumentedmatlab.com/blog_old/matlab-toolstrip-part-8-galleries https://undocumentedmatlab.com/blog_old/matlab-toolstrip-part-8-galleries#comments Sun, 03 Feb 2019 17:00:55 +0000 https://undocumentedmatlab.com/?p=8321 Related posts:
  1. Matlab toolstrip – part 2 (ToolGroup App) Matlab users can create custom Apps with toolstrips and docked figures. ...
  2. Matlab toolstrip – part 3 (basic customization) Matlab toolstrips can be created and customized in a variety of ways. ...
  3. Matlab toolstrip – part 4 (control customization) Matlab toolstrip components (controls) can be customized in various ways, including user-defined callbacks. ...
  4. Matlab toolstrip – part 6 (complex controls) Multiple types of customizable controls can be added to Matlab toolstrips...
]]>
In previous posts I showed how we can create custom Matlab app toolstrips using various controls (buttons, checkboxes, drop-downs, lists etc.). Today I will show how we can incorporate gallery panels into our Matlab toolstrip.
Toolstrip Gallery (in-line & drop-down)

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.

Also, remember to add the following code snippet at the beginning of your code so that the relevant toolstrip classes will be recognized by Matlab:

import matlab.ui.internal.toolstrip.*

Gallery sub-components

Toolstrip gallery popup components

Toolstrip gallery popup components

Toolstrip galleries are panels of buttons (typically large icons with an attached text label), which are grouped in “categories”. The gallery content can be presented either in-line within the toolstrip (a Gallery control), or as a drop-down button’s popup panel (a DropDownGalleryButton control). In either case, the displayed popup panel is a GalleryPopup object, that is composed of one or more GalleryCategory, each of which has one or more GalleryItem (push-button) and/or ToggleGalleryItem (toggle-button).

  • Gallery or DropDownGalleryButton
    • GalleryPopup
      • GalleryCategory
        • GalleryItem or ToggleGalleryItem
        • GalleryItem or ToggleGalleryItem
      • GalleryCategory

For a demonstration of toolstrip Galleries, see the code files in %matlabroot%/toolbox/matlab/toolstrip/+matlab/+ui/+internal/+desktop/, specifically showcaseToolGroup.m and showcaseBuildTab_Gallery.m.

GalleryPopup

We first create the GalleryPopup object, then add to it a few GalleryCategory groups of GalleryItem, ToggleGalleryItem buttons. In the example below, we use a ButtonGroup to ensure that only a single ToggleGalleryItem button is selected:

import matlab.ui.internal.toolstrip.*
popup = GalleryPopup('ShowSelection',true);
 
% Create gallery categories
cat1 = GalleryCategory('CATEGORY #1 SINGLE'); popup.add(cat1);
cat2 = GalleryCategory('CATEGORY #2 SINGLE'); popup.add(cat2);
cat3 = GalleryCategory('CATEGORY #3 SINGLE'); popup.add(cat3);
 
% Create a button-group to control item selectability
group = matlab.ui.internal.toolstrip.ButtonGroup;
 
% Add items to the gallery categories
fpath = [fullfile(matlabroot,'toolbox','matlab','toolstrip','web','image') filesep];  % icons path
 
item1 = ToggleGalleryItem('Biology', Icon([fpath 'biology_app_24.png']), group);
item1.Description = 'Select the Biology gizmo';
item1.ItemPushedFcn = @(x,y) ItemPushedCallback(x,y);
cat1.add(item1);
 
item2 = ToggleGalleryItem('Code Generation', Icon([fpath 'code_gen_app_24.png']), group);
cat1.add(item2);
 
item3 = ToggleGalleryItem('Control', Icon([fpath 'control_app_24.png']), group);
cat1.add(item3);
 
item4 = ToggleGalleryItem('Database', Icon([fpath 'database_app_24.png']), group);
cat1.add(item4);
...

Single-selection GalleryPopup (icon view)

Single-selection GalleryPopup (icon view)

Note that in a real-world situation, we’d assign a Description, Tag and ItemPushedFcn to all gallery items. This was elided from the code snippet above for readability, but should be part of any actual GUI. The Description only appears as tooltip popup in icon-view (shown above), but appears as a visible label in list-view (see below).

Gallery items selection: push-button action, single-selection toggle, multiple selection toggle

If we use ToggleGalleryItem without a ButtonGroup, multiple gallery items can be selected, rather than just a single selection as shown above:

...
item1 = ToggleGalleryItem('Biology', Icon([fpath 'biology_app_24.png']));item1.Description = 'Select the Biology gizmo';
item1.ItemPushedFcn = @(x,y) ItemPushedCallback(x,y);
cat1.add(item1);
 
item2 = ToggleGalleryItem('Code Generation', Icon([fpath 'code_gen_app_24.png']));cat1.add(item2);
 
item3 = ToggleGalleryItem('Control', Icon([fpath 'control_app_24.png']));cat1.add(item3);
 
item4 = ToggleGalleryItem('Database', Icon([fpath 'database_app_24.png']));cat1.add(item4);
...

Multiple-selection GalleryPopup (icon view)

Multiple-selection GalleryPopup (icon view)

Alternatively, if we use GalleryItem instead of ToggleGalleryItem, the gallery items would be push-buttons rather than toggle-buttons. This enables us to present a gallery of single-action state-less push-buttons, rather than state-full toggle-buttons. The ability to customize the gallery items as either state-less push-buttons or single/multiple toggle-buttons supports a wide range of application use-cases.

Customizing the GalleryPopup

Properties that affect the GalleryPopup appearance are:

  • DisplayState – initial display mode of gallery items (string; default=’icon_view’, valid values: ‘icon_view’,’list_view’)
  • GalleryItemRowCount – number of rows used in the display of the in-line gallery (integer; default=1, valid values: 0,1,2). A Value of 2 should typically be used with a small icon and GalleryItemWidth (see below)
  • GalleryItemTextLineCount – number of rows used for display of the item label (integer; default=2, valid values: 0,1,2)
  • ShowSelection – whether or not to display the last-selected item (logical; default=false). Needs to be true for Gallery and false for DropDownGalleryButton.
  • GalleryItemWidth – number of pixels to allocate for each gallery item (integer, hidden; default=80)
  • FavoritesEnabled – whether or not to enable a “Favorites” category (logical, hidden; default=false)

All of these properties are defined as private in the GalleryPopup class, and can only be specified during the class object’s construction. For example, instead of the default icon-view, we can display the gallery items as a list, by setting the GalleryPopup‘s DisplayState property to 'list_view' during construction:

popup = GalleryPopup('DisplayState','list_view');

GalleryPopup (list view)

GalleryPopup (list view)


Switching from icon-view to list-view and back can also be done by clicking the corresponding icon near the popup’s top-right corner (next to the interactive search-box).

Now that we have prepared GalleryPopup, let’s integrate it in our toolstrip.
We have two choices — either in-line within the toolstrip section (using Gallery), or as a compact drop-down button (using DropDownGalleryButton):

% Inline gallery
section = hTab.addSection('Multiple Selection Gallery');
column = section.addColumn();
popup = GalleryPopup('ShowSelection',true);
% add the GalleryPopup creation code above
gallery = Gallery(popup, 'MinColumnCount',2, 'MaxColumnCount',4);
column.add(gallery);
 
% Drop-down gallery
section = hTab.addSection('Drop Down Gallery');
column = section.addColumn();
popup = GalleryPopup();
% add the GalleryPopup creation code above
button = DropDownGalleryButton(popup, 'Examples', Icon.MATLAB_24);
button.MinColumnCount = 5;
column.add(button);

Toolstrip Gallery (in-line & drop-down)

Clicking any of the drop-down (arrow) widgets will display the associated GalleryPopup.

The Gallery and DropDownGalleryButton objects have several useful settable properties:

  • Popup – a GalleryPopup object handle, which is displayed when the user clicks the drop-down (arrow) widget. Only settable in the constructor, not after object creation.
  • MinColumnCount – minimum number of item columns to display (integer; default=1). In Gallery, this property is only settable in the constructor, not after object creation; if not enough width is available to display these columns, the control collapses into a drop-down. In DropDownGalleryButton, this property can be set even after object creation (despite incorrect internal documentation), and controls the width of the popup panel.
  • MaxColumnCount – maximal number of items columns to display (integer; default=10). In Gallery, this property is only settable in the constructor, not after object creation. In DropDownGalleryButton, this property can be set even after object creation but in any case seems to have no visible effect.
  • Description – tooltip text displayed when the mouse hovers over the Gallery area (outside the area of the internal gallery items, which have their own individual Descriptions), or over the DropDownGalleryButton control.
  • TextOverlay – a semi-transparent text label overlaid on top of the gallery panel (string, default=”). Only available in Gallery, not DropDownGalleryButton.

For example:

gallery = Gallery(popup, 'MinColumnCount',2, 'MaxColumnCount',4);
gallery.TextOverlay = 'Select from these items';

Effect of TextOverlay

Effect of TextOverlay

Toolstrip miniseries roadmap

The next post will discuss popup forms. These are similar in concept to galleries, in the sense that when we click the drop-down widget a custom popup panel is displayed. In the case of a popup form, this is a fully-customizable Matlab GUI figure.

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-8-galleries/feed 5
Matlab toolstrip – part 7 (selection controls)https://undocumentedmatlab.com/blog_old/matlab-toolstrip-part-7-selection-controls https://undocumentedmatlab.com/blog_old/matlab-toolstrip-part-7-selection-controls#comments Sun, 27 Jan 2019 17:00:34 +0000 https://undocumentedmatlab.com/?p=8257 Related posts:
  1. Matlab toolstrip – part 2 (ToolGroup App) Matlab users can create custom Apps with toolstrips and docked figures. ...
  2. Matlab toolstrip – part 3 (basic customization) Matlab toolstrips can be created and customized in a variety of ways. ...
  3. Matlab toolstrip – part 4 (control customization) Matlab toolstrip components (controls) can be customized in various ways, including user-defined callbacks. ...
  4. Matlab toolstrip – part 6 (complex controls) Multiple types of customizable controls can be added to Matlab toolstrips...
]]>
In previous posts I showed how we can create custom Matlab app toolstrips using controls such as buttons, checkboxes, sliders and spinners. Today I will show how we can incorporate even more complex selection controls into our toolstrip: lists, drop-downs, popups etc.
Toolstrip SplitButton with dynamic popup and static sub-menu

Toolstrip SplitButton with dynamic popup and static sub-menu

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.

Also, remember to add the following code snippet at the beginning of your code so that the relevant toolstrip classes will be recognized by Matlab:

import matlab.ui.internal.toolstrip.*

There are 4 types of popups in toolstrip controls:

  1. Builtin dropdown (combo-box) selector similar to the familiar uicontrol(‘style’,’popup’,…). In toolstrips, this is implemented using the DropDown control.
  2. A more complex dropdown selector having icons and tooltips, implemented using the DropDownButton and SplitButton toolstrip controls.
  3. An even-more complex drop-down selector, which presents a gallery of options. This will be discussed in detail in the next post.
  4. A fully-customizable form panel (“popup form”). This will be discussed separately, in the following post.

The simple DropDown toolstrip control is very easy to set up and use:

hPopup = DropDown({'Label1';'Label2';'Label3'});
hPopup.Value = 'Label3';
hPopup.ValueChangedFcn = @ValueChangedCallback;

Toolstrip DropDown

Toolstrip DropDown

Note that the drop-down items (labels) need to be specified as a column cell-array (i.e. {a;b;c}) – a row cell-array ({a,b,c}) will result in run-time error.

We can have the control hold a different value for each of the displayed labels, by specifying the input items as an Nx2 cell-array:

items = {'One',   'Label1'; ...
         'Two',   'Label2'; ...
         'Three', 'Label3'}
hPopup = DropDown(items);
hPopup.Value = 'Two';
hPopup.ValueChangedFcn = @ValueChangedCallback;

This drop-down control will display the labels “Label1”, “Label2” (initially selected), and “Label3”. Whenever the selected drop-down item is changed, the corresponding popup Value will change to the corresponding value. For example, when “Label3” is selected in the drop-down, hPopup.Value will change to ‘Three’.

Another useful feature of the toolstrip DropDown control is the Editable property (logical true/false, default=false), which enables the user to modify the entry in the drop-down’s editbox. Any custom text entered within the editbox will update the control’s Value property to that string.

ListBox

We can create a ListBox in a very similarly manner to DropDown. For example, the following code snippet creates a list-box that spans the entire toolstrip column height and has 2 of its items initially selected:

hColumn = hSection.addColumn('Width',100);
allowMultiSelection = true;
items = {'One','Label1'; 'Two','Label2'; 'Three','Label3'; 'Four','Label4'; 'Five','Label5'};
hListBox = ListBox(items, allowMultiSelection);
hListBox.Value = {'One'; 'Three'};
hListBox.ValueChangedFcn = @ValueChangedCallback;
hColumn.add(hListBox);

Toolstrip ListBox (multi-selection)

Toolstrip ListBox (multi-selection)

The DropDown and ListBox controls are nearly identical in terms of their properties, methods and events/callbacks, with the following notable exceptions:

  • ListBox controls do not have an Editable property
  • ListBox controls have a MultiSelect property (logical, default=false), which DropDowns do not have. Note that this property can only be set during the ListBox‘s creation, as shown in the code snippet above.

DropDownButton and SplitButton

A more elaborate drop-down selector can be created using the DropDownButton and SplitButton toolstrip controls. For such controls, we create a PopupList object, and add elements to it, which could be any of the following, in whichever order that you wish:

  1. PopupListHeader – a section header (title), non-selectable
  2. ListItem – a selectable list item, with optional Icon, Text, and Description (tooltip string, which for some reason [probably a bug] is not actually shown). For some reason (perhaps a bug), the Description is not shown in a tooltip (no tooltip is displayed). However, it is displayed as a label beneath the list-item’s main label, unless we set ShowDescription to false.
  3. ListItemWithCheckBox – a selectable list item that toggles a checkmark icon based on the list item’s selection Value (on/off). The checkmark icon is not customizable (alas).
  4. ListItemWithPopup – a non-selectable list item, that displays a sub-menu (another PopupList that should be set to the parent list-item’s Popup property).

A simple usage example (adapted from the showcaseToolGroup demo):

Toolstrip PopupList

Toolstrip PopupList

function hPopup = createPopup()
 
    import matlab.ui.internal.toolstrip.*
    hPopup = PopupList();
 
    % list header #1
    header = PopupListHeader('List Items');
    hPopup.add(header);
 
    % list item #1
    item = ListItem('This is item 1', Icon.MATLAB_16);
    item.Description = 'this is the description for item #1';
    item.ShowDescription = true;
    item.ItemPushedFcn = @ActionPerformedCallback;
    hPopup.add(item);
 
    % list item #2
    item = ListItem('This is item 2', Icon.SIMULINK_16);
    item.Description = 'this is the description for item #2';
    item.ShowDescription = false;
    addlistener(item, 'ItemPushed', @ActionPerformedCallback);
    hPopup.add(item);
 
    % list header #2
    header = PopupListHeader('List Item with Checkboxes');
    hPopup.add(header);
 
    % list item with checkbox
    item = ListItemWithCheckBox('This is item 3', true);
    item.ValueChangedFcn = @PropertyChangedCallback;
    hPopup.add(item);
 
    % list item with popup
    item = ListItemWithPopup('This is item 4',Icon.ADD_16);
    item.ShowDescription = false;
    hPopup.add(item);
 
    % Sub-popup
    hSubPopup = PopupList();
    item.Popup = hSubPopup;
    % sub list item #1
    sub_item1 = ListItem('This is sub item 1', Icon.MATLAB_16);
    sub_item1.ShowDescription = false;
    sub_item1.ItemPushedFcn = @ActionPerformedCallback;
    hSubPopup.add(sub_item1);
    % sub list item #2
    sub_item2 = ListItem('This is sub item 2', Icon.SIMULINK_16);
    sub_item2.ShowDescription = false;
    sub_item2.ItemPushedFcn = @ActionPerformedCallback;
    hSubPopup.add(sub_item2);
 
end  % createPopup()

We now have two alternatives for attaching this popup to the DropDownButton or SplitButton:

Toolstrip SplitButton with dynamic popup and static sub-menu

Toolstrip SplitButton with dynamic popup and static sub-menu

  • Static popup – set the Popup property of the button or ListItemWithPopup to the popup-creation function (or hPopup). The popup will be created once and will remain unchanged throughout the program execution. For example:
    hButton = DropDownButton('Vertical', Icon.OPEN_24);
    hButton.Popup = createPopup();
  • Dynamic popup – set the DynamicPopupFcn of the button or ListItemWithPopup to the popup creation function. This function will be invoked separately whenever the user clicks on the drop-down selector widget. Inside our popup-creation function we can have state-dependent code that modifies the displayed list items depending on the state of our program/environment. For example:
    hButton = SplitButton('Vertical', Icon.OPEN_24);
    hButton.ButtonPushedFcn = @ActionPerformedCallback;  % invoked when user clicks the main split-button part
    hButton.DynamicPopupFcn = @(h,e) createPopup();      % invoked when user clicks the drop-down selector widget


DropDownButton and SplitButton are exactly the same as far as the popup-list is concerned: If it is set via the Popup property then the popup is static (in the sense that it is only evaluated once, when created), and if it is set via DynamicPopupFcn then the popup is dynamic (re-created before display). The only difference between DropDownButton and SplitButton is that in addition to the drop-down control, a SplitButton also includes a regular push-button control (with its corresponding ButtonPushedFcn callback).

In summary:

  • If DynamicPopupFcn is set to a function handle, then the PopupList that is returned by that function will be re-evaluated and displayed whenever the user clicks the main button of a DropDownButton or the down-arrow part of a SplitButton. This happens even if the Popup property is also set i.e., DynamicPopupFcn has precedence over Popup; when both of them are set, Popup is silently ignored (it would be useful for Matlab to display a warning in such cases, hopefully in a future release).
  • If DynamicPopupFcn is not set but Popup is (to a PopupList object handle), then this PopupList will be computed only once (when first created) and then it will be displayed whenever the user clicks the main button of a DropDownButton or the down-arrow part of a SplitButton.
  • Separately from the above, if a SplitButton‘s ButtonPushedFcn property is set to a function handle, then that function will be evaluated whenever the user clicks the main button of the SplitButton. No popup is presented, unless of course the callback function displays a popup programmatically. Note that ButtonPushedFcn is a property of SplitButton; this property does not exist in a DropDownButton.

Important note: whereas DropDown and ListBox have a ValueChangedFcn callback that is invoked whenever the drop-down/listbox Value has changed, the callback mechanism is very different with DropDownButton and SplitButton: here, each menu item has its own individual callback that is invoked when that item is selected (clicked): ItemPushedFcn for ListItem; ValueChangedFcn for ListItemWithCheckBox; and DynamicPopupFcn for ListItemWithPopup. As we shall see later, the same is true for gallery items – each item has its own separate callback.

Galleries

Toolstrip galleries are panels of buttons (typically large icons with an attached text label), which are grouped in “categories”.

The general idea is to first create the GalleryPopup object, then add to it a few GalleryCategory groups, each consisting of GalleryItem (push-buttons) and/or ToggleGalleryItem (toggle-buttons) objects. Once this GalleryPopup is created, we can either integrate it in-line within the toolstrip section (using Gallery), or as a compact drop-down button (using DropDownGalleryButton):

% Inline gallery
section = hTab.addSection('Multiple Selection Gallery');
column = section.addColumn();
popup = GalleryPopup('ShowSelection',true);
% add the GalleryPopup creation code (see next week's post)
gallery = Gallery(popup, 'MaxColumnCount',4, 'MinColumnCount',2);
column.add(gallery);
 
% Drop-down gallery
section = hTab.addSection('Drop Down Gallery');
column = section.addColumn();
popup = GalleryPopup();
% add the GalleryPopup creation code (see next week's post)
button = DropDownGalleryButton(popup, 'Examples', Icon.MATLAB_24);
button.MinColumnCount = 5;
column.add(button);

Toolstrip Gallery (in-line & drop-down)

I initially planned to include all the relevant Gallery discussion here, but it turned out to require so much space that I decided to devote a separate article for it — this will be the topic of next week’s blog post.

Toolstrip miniseries roadmap

The next post will discuss Galleries in depth, followed by popup forms.

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-7-selection-controls/feed 6
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
Reverting axes controls in figure toolbarhttps://undocumentedmatlab.com/blog_old/reverting-axes-controls-in-figure-toolbar https://undocumentedmatlab.com/blog_old/reverting-axes-controls-in-figure-toolbar#comments Sun, 23 Dec 2018 19:52:19 +0000 https://undocumentedmatlab.com/?p=8171 Related posts:
  1. uiundo – Matlab’s undocumented undo/redo manager The built-in uiundo function provides easy yet undocumented access to Matlab's powerful undo/redo functionality. This article explains its usage....
  2. Docking figures in compiled applications Figures in compiled applications cannot officially be docked since R2008a, but this can be done using a simple undocumented trick....
  3. Toolbar button labels GUI toolbar button labels can easily be set and customized using underlying Java components. ...
  4. Customizing figure toolbar background Setting the figure toolbar's background color can easily be done using just a tiny bit of Java magic powder. This article explains how. ...
]]>
I planned to post a new article in my toolstrip mini-series, but then I came across something that I believe has a much greater importance and impacts many more Matlab users: the change in Matlab R2018b’s figure toolbar, where the axes controls (zoom, pan, rotate etc.) were moved to be next to the axes, which remain hidden until you move your mouse over the axes. Many users have complained about this unexpected change in the user interface of such important data exploration functionality:

R2018a (standard toolbar)

R2018a (standard toolbar)

R2018b (integrated axes toolbar)

R2018b (integrated axes toolbar)

Luckily, we can revert the change, as was recently explained in this Answers thread:

addToolbarExplorationButtons(gcf) % Add the axes controls back to the figure toolbar
 
hAxes.Toolbar.Visible = 'off'; % Hide the integrated axes toolbar
%or:
hAxes.Toolbar = []; % Remove the axes toolbar data

And if you want to make these changes permanent (in other words, so that they would happen automatically whenever you open a new figure or create a new axes), then add the following code snippet to your startup.m file (in your Matlab startup folder):

try %#ok
    if ~verLessThan('matlab','9.5')
        set(groot,'defaultFigureCreateFcn',@(fig,~)addToolbarExplorationButtons(fig));
        set(groot,'defaultAxesCreateFcn',  @(ax,~)set(ax.Toolbar,'Visible','off'));
    end
end

MathWorks is taking a lot of heat over this change, and I agree that it could have done a better job of communicating the workaround in placing it as settable configurations in the Preferences panel or elsewhere. Whenever an existing functionality is broken, certainly one as critical as the basic data-exploration controls, MathWorks should take extra care to enable and communicate workarounds and settable configurations that would enable users a gradual smooth transition. Having said this, MathWorks does communicate the workaround in its release notes (I’m not sure whether this was there from the very beginning or only recently added, but it’s there now).

In my opinion the change was *not* driven by the marketing guys (as was the Desktop change from toolbars to toolstrip back in 2012 which received similar backlash, and despite the heated accusations in the above-mentioned Answers thread). Instead, I believe that this change was technically-driven, as part of MathWorks’ ongoing infrastructure changes to make Matlab increasingly web-friendly. The goal is that eventually all the figure functionality could transition to Java-script -based uifigures, replacing the current (“legacy”) Java-based figures, and enabling Matlab to work remotely, via any browser-enabled device (mobiles included), and not be tied to desktop operating systems. In this respect, toolbars do not transition well to webpages/Javascript, but the integrated axes toolbar does. Like it or not, eventually all of Matlab’s figures will become web-enabled content, and this is simply one step in this long journey. There will surely be other painful steps along the way, but hopefully MathWorks would learn a lesson from this change, and would make the transition smoother in the future.

Once you regain your composure and take the context into consideration, you might wish to let MathWorks know what you think of the toolbar redesign here. Please don’t complain to me – I’m only the messenger…

Merry Christmas everybody!

p.s. One of the complaints against the new axes toolbar is that it hurts productivity by forcing users to wait for the toolbar to fade-in and become clickable. Apparently the axes toolbar has a hidden private property called FadeGroup that presumably controls the fade-in/out effect. This can be accessed as follows:

hFadeGroup = struct(hAxes.Toolbar).FadeGroup  % hAxes is the axes handle

I have not [yet] discovered if and how this object can be customized to remove the fade animation or control its duration, but perhaps some smart hack would discover and post the workaround here (or let me know in a private message that I would then publish anonymously).

]]>
https://undocumentedmatlab.com/blog_old/reverting-axes-controls-in-figure-toolbar/feed 6
Matlab toolstrip – part 3 (basic customization)https://undocumentedmatlab.com/blog_old/matlab-toolstrip-part-3-basic-customization https://undocumentedmatlab.com/blog_old/matlab-toolstrip-part-3-basic-customization#comments Sun, 16 Dec 2018 16:00:29 +0000 https://undocumentedmatlab.com/?p=8077 Related posts:
  1. Matlab toolstrip – part 2 (ToolGroup App) Matlab users can create custom Apps with toolstrips and docked figures. ...
  2. Matlab toolstrip – part 4 (control customization) Matlab toolstrip components (controls) can be customized in various ways, including user-defined callbacks. ...
  3. Matlab toolstrip – part 6 (complex controls) Multiple types of customizable controls can be added to Matlab toolstrips...
  4. Matlab toolstrip – part 7 (selection controls) Matlab toolstrips can contain a wide variety of selection controls: popups, combo-boxes, and galleries. ...
]]>
In the previous post I showed how we can create custom Matlab apps. In such apps, the toolstrip is very often an important part. Today I continue my miniseries on toolstrips. Toolstrips can be a bit complex so I’m trying to proceed slowly, with each post in the miniseries building on the previous posts. So I encourage you to review the earlier posts in the miniseries (part1, part2) before reading this post.

A Matlab toolstrip is composed of a hierarchy of user-interface objects as follows (all objects are classes within the matlab.ui.internal.toolstrip package):

Anatomy of a Matlab app with toolstrip

Anatomy of a Matlab app with toolstrip

  • TabGroup
    • Tab
      • Section
        • Column
          • Component
            • Component
          • Column
        • Section
      • Tab
    • TabGroup

    In this post I explain how we can create a custom toolstrip that contains tabs, sections, and basic controls that interact with the user and the docked figures. The following posts will show more advanced customizations and more complex controls, as well as showing alternative ways of creating the toolstrip.

    1. Creating a bare toolstrip and new tabs

    We start with a new ToolGroup that has a bare toolstrip and a docked figure (for details and explanations refer to the previous post):

    % Create a new ToolGroup ("app") with a hidden DataBrowser
    hToolGroup = matlab.ui.internal.desktop.ToolGroup('Toolstrip example on UndocumentedMatlab.com');
    hToolGroup.disableDataBrowser();
    hToolGroup.open();  % this may be postponed further down for improved performance
     
    % Store toolgroup reference handle so that app will stay in memory
    jToolGroup = hToolGroup.Peer;
    internal.setJavaCustomData(jToolGroup, hToolGroup);
     
    % Create two figures and dock them into the ToolGroup
    hFig1 = figure('Name','3D');  surf(peaks);
    hToolGroup.addFigure(hFig1);

    We now create a new TabGroup and and it to our ToolGroup:

    import matlab.ui.internal.toolstrip.*  % for convenience below
    hTabGroup = TabGroup();
    hToolGroup.addTabGroup(hTabGroup);

    We can add a new Tab to the TabGroup using either of two methods:

    1. Create a new Tab object and then use TabGroup.add(hTab,index) to add it to a parent TabGroup. The index argument is optional – if specified the section is inserted at that index location; if not, it is added at the end of the tab-group. Sample usage:
      hTab = Tab('Data');
      hTabGroup.add(hTab);  % add to tab as the last section
      hTabGroup.add(hTab,3);  % add to tab as the 3rd section
    2. Call TabGroup.addTab(title). This creates a new tab with the specified title (default: ”) and adds it at the end of the tab-group. The new tab’s handle is returned by the function. Sample usage:
      hTabGroup.addTab('Data');  % add to tab-group as the last tab

    This creates an empty “Data” tab in our app toolstrip. Note that the tab title is capitalized (“DATA”), despite the fact that we set its Title property to 'Data'. Also note that while the tab’s Title property can be updated after the tab is created, in practice the tab title does not seem to change.

    New (empty) toolstrip tab

    Lastly, note that a “VIEW” tab is automatically added to our toolstrip. As explained in the previous post, we can remove it using hToolGroup.hideViewTab; (refer to the previous post for details).

    2. Adding sections to a toolstrip tab

    Each toolstrip Tab is composed of Sections, that holds the actual components. We cannot add components directly to a Tab: they have to be contained within a Section. A toolstrip Tab can only contain Sections as direct children.

    We can add a new section to a Tab using either of two methods, in a similar way to the that way we added a new tab above:

    1. Create a new Section object and then use Tab.add(hSection,index) to add it to a parent Tab. The index argument is optional – if specified the section is inserted at that index location; if not, it is added at the end of the tab. Sample usage:
      hSection = Section('Section title');
      hTab.add(hSection);  % add to tab as the last section
      hTab.add(hSection,3);  % add to tab as the 3rd section
    2. Call Tab.addSection(title). This creates a new section with the specified title (default: ”) and adds it at the end of the tab. The new section’s handle is returned by the function. Sample usage:
      hTab.addSection('Section title');  % add to tab as the last section

    Note that the help section for Tab.addSection() indicates that it’s possible to specify 2 string input args (presumably Title and Tag), but this is in fact wrong and causes a run-time error, since Section constructor only accepts a single argument (Title), at least as of R2018b.

    The Section‘s Title property can be set both in the constructor, as well as updated later. In addition, we can also set the Tag and CollapsePriority properties after the section object is created (these properties cannot be set in the constructor call):

    hSection.Title = 'New title';    % can also be set in constructor call
    hSection.Tag = 'section #1';     % cannot be set in constructor call
    hSection.CollapsePriority = 10;  % cannot be set in constructor call

    The CollapsePriority property is responsible for controlling the order in which sections and their internal components collapse into a drop-down when the window is resized to a smaller width.

    Like tabs, section titles also appear capitalized. However, unlike the section titles can indeed be modified in run-time.

    3. Adding columns to a tab section

    Each Section in a toolstrip Tab is composed of Columns, and each Column can contain 1-3 Components. This is a very effective layout for toolstrip controls that answers the vast majority of use-cases. In some special cases we might need more flexibility with the component layout within a Tab – I will explain this in a future post. But for now let’s stick to the standard Tab-Section-Column-Component framework.

    We can add columns to a section using (guess what?) either of two methods, as above:

    1. Create a new Column object and then use Section.add(hColumn,index) to add it to a parent Section. The index argument is optional – if specified the column is inserted at that index location; if not, it is added at the end of the section. Sample usage:
      hColumn = Column('HorizontalAlignment','center', 'Width',150);
      hSection.add(hColumn);  % add to section as the last column
      hSection.add(hColumn,3);  % add to section as the 3rd column
    2. Call Tab.addSection(title). This creates a new section with the specified title (default: ”) and adds it at the end of the tab. The new section’s handle is returned by the function. Sample usage:
      hSection.addColumn('HorizontalAlignment','center', 'Width',150);  % add to section as the last column

    We can set the Column‘s HorizontalAlignment and Width properties only in the constructor call, not later via direct assignments. In contrast, the Tag property cannot be set in the constructor, only via direct assignment:

    hColumn.HorizontalAlignment = 'right';  % error: can only be set via constructor call: Column('HorizontalAlignment','right', ...)
    hColumn.Width = 150;                    % error: can only be set via constructor call: Column('Width',150, ...)
    hColumn.Tag = 'column #2';              % ok: cannot be set via the constructor call!

    This is indeed confusing and non-intuitive. Perhaps this is part of the reason that the toolstrip API is still not considered stable enough for a general documented release.

    4. Adding controls to a section column

    Each section column contains 1 or more Components. These can be push/toggle/split/radio buttons, checkboxes, drop-downs, sliders, spinners, lists etc. Take a look at matlabroot%/toolbox/matlab/toolstrip/+matlab/+ui/+internal/+toolstrip/ for a full list of available controls. I’ll discuss a few basic controls in this post, and more complex ones in future posts.

    As above, there are two methods for adding components to a section column, but they have different purposes:

    1. Column.addEmptyControl() adds a filler space in the next position of the column. This is used to display the colorbar control at the center of the column in the usage snippet below.
    2. Create a new Component object and then use Column.add(hComponent, index) to add it to a parent Column. The index argument is optional – if specified the component is inserted at that index location; if not, it is added at the end of the column. Sample usage:
      hButton = Button('Click me!');
      hColumn.add(hButton);  % add to column as the last component
      hColumn.add(hButton,3);  % add to column as the 3rd component

    Component objects (matlab.ui.internal.toolstrip.base.Component, which all usable toolstrip controls inherit) have several common properties. Leaving aside the more complex components for now, most usable controls include the following properties:

    • Text – text label, displayed next to the control icon (pity that MathWorks didn’t call this property String or Label, in line with uicontrols/menu-items)
    • Description – tooltip, displayed when hovering the mouse over the control (pity that MathWorks didn’t call this property Tooltip in line with uicontrols/menu-items)
    • Tag – a string, as all other Matlab HG objects. Controls are searchable by their Tag via their container’s find(tag) and findAll(tag) methods (again, I don’t quite understand why not use findobj and findall as with the rest of Matlab HG…).
    • Enabled – a logical value (true/false), true by default
    • Icon – the icon used next to the Text label. We can use the Icon constructor (that expects the full path of a PNG/JPG file), or one of its static icons (e.g. Icon.REFRESH_16). Icons will be discussed in detail in the following post; in the meantime you can see various usage examples below.

    Each control also has one or more callbacks that can be specified, as settable properties and/or as events that can be listened-to using the addlistener function. This too will be discussed in detail in the next post, but in the meantime you can see various usage examples below.

    Columns can have 1-3 components:

    • If only 1 component is specified, it is allocated the full column height, effectively creating a large control, with the Icon on top (typically a 24×24 icon) and the Text label beneath.
    • If 2 or 3 components are specified, then smaller controls are displayed, with the Text label to the right of the Icon (typically 16×16), and the controls evenly spaced within the column.
    • If you try to add more than 3 components to a Column, you’ll get a run-time error.

    5. Usage example

    Here is a short usage example showing the above concepts. The code is not pretty by any means – I intentionally wanted to display multiple different ways of adding components, specifying properties and callbacks etc. It is meant merely as an educational tool, and is not close to being ready for production code. So please don’t complain about the known fact that the code is ugly, non-robust, and in general exhibits bad programming practices. The complete runnable code can be downloaded here.

    The following code snippets assume that you have already ran the code in paragraph 1 above:

    Push-buttons section (3 columns)
    Toolstrip example (basic controls)

    Toolstrip example (basic controls)

    section1 = hTab.addSection('Push buttons');
     
    column1a = section1.addColumn();
    icon = Icon.REFRESH_24; % built-in: see Icon.showStandardIcons()
    button = Button('Refresh all',icon);
    button.Description = 'Refresh the charted data - all axes';
    button.ButtonPushedFcn = @refreshAllData;
    column1a.add(button);
    function refreshAllData(hAction,hEventData)
        hAxes = gca;
        hChildren = hAxes.Children;
        for idx = 1 : numel(hChildren)
            hChild = hChildren(idx);
            hChild.XData = -hChild.XData;
            hChild.YData = -hChild.YData;
            hChild.ZData = -hChild.ZData;
        end
    end
     
    column1b = section1.addColumn();
    addRefresh2Button('X','Y');
    addRefresh2Button('Y','Z');
    function addRefresh2Button(type1, type2)
        import matlab.ui.internal.toolstrip.*
        hButton = Button(['Refresh ' type1 ',' type2], Icon.RESTORE_16);
        hButton.Description = ['Refresh the charted data - ' type1 ',' type2 ' axes'];
        hButton.ButtonPushedFcn = {@refres2AxisData, type1, type2};
        column1b.add(hButton);
     
        function refres2AxisData(~,~,type1,type2)
            hAxes = gca;
            hChildren = hAxes.Children;
            for idx = 1 : numel(hChildren)
                hChild = hChildren(idx);
                hChild.([type1 'Data']) = -hChild.([type1 'Data']);
                hChild.([type2 'Data']) = -hChild.([type2 'Data']);
            end
        end
    end
     
    column1c = section1.addColumn();
    addRefresh1Button('X');
    addRefresh1Button('Y');
    addRefresh1Button('Z');
    function addRefresh1Button(type)
        import matlab.ui.internal.toolstrip.*
        hButton = Button(['Refresh ' type], Icon.REDO_16);
        hButton.Description = ['Refresh the charted data - ' type ' axes'];
        addlistener(hButton, 'ButtonPushed', @refres1AxisData);  % {} not supported!
        column1c.add(hButton);
     
        function refres1AxisData(h,e)
            hAxes = gca;
            hChildren = hAxes.Children;
            for idx = 1 : numel(hChildren)
                hChild = hChildren(idx);
                hChild.([type 'Data']) = -hChild.([type 'Data']);
            end
        end
    end
    Toggle buttons section (2 columns)
    section2 = hTab.addSection('Toggle buttons');
    section2.CollapsePriority = 2;
     
    column1 = Column();
    section2.add(column1);
    %icon = Icon.LEGEND_24;
    icon = Icon(fullfile(matlabroot,'toolbox','shared','controllib','general','resources','toolstrip_icons','Legend_24.png')); % PNG/JPG image file (not GIF!)
    button = ToggleButton('Legend',icon);
    button.Description = 'Toggle legend display';
    addlistener(button, 'ValueChanged', @(h,e)legend('toggle'));
    column1.add(button);
     
    column2 = section2.addColumn();
    imagefile = fullfile(matlabroot,'toolbox','matlab','icons','tool_colorbar.png');
    jIcon = javax.swing.ImageIcon(imagefile); % Java ImageIcon from file (inc. GIF)
    %jIcon = javax.swing.ImageIcon(jIcon.getImage.getScaledInstance(24,24,jIcon.getImage.SCALE_SMOOTH))  % Resize icon to 24x24
    icon = Icon(jIcon);
    button = ToggleButton('Colorbar',icon);
    button.Description = 'Toggle colorbar display';
    button.ValueChangedFcn = @toggleColorbar;
    column2.addEmptyControl();
    column2.add(button);
    column2.addEmptyControl();
    function toggleColorbar(hAction,hEventData)
        if hAction.Selected
            colorbar;
        else
            colorbar('off');
        end
    end
    Checkboxes section (1 column 150px-wide), placed after the push-buttons section
    section3 = Section('Checkboxes');
    section3.CollapsePriority = 1;
    hTab.add(section3, 2);
     
    column3 = section3.addColumn('HorizontalAlignment','left', 'Width',150);
     
    button = CheckBox('Axes borders', true);
    button.ValueChangedFcn = @toggleAxes;
    button.Description = 'Axes borders';
    column3.add(button);
    function toggleAxes(hAction,hEventData)
        if hAction.Selected
            set(gca,'Visible','on');
        else
            set(gca,'Visible','off');
        end
    end
     
    button = CheckBox('Log scaling', false);
    button.addlistener('ValueChanged',@toggleLogY);
    button.Description = 'Log scaling';
    column3.add(button);
    function toggleLogY(hCheckbox,hEventData)
        if hCheckbox.Value, type = 'log'; else, type = 'linear'; end
        set(gca, 'XScale',type, 'YScale',type, 'ZScale',type);
    end
     
    button = CheckBox('Inverted Y', false);
    button.addlistener('ValueChanged',@toggleInvY);
    button.Description = 'Invert Y axis';
    column3.add(button);
    function toggleInvY(hCheckbox,~)
        if hCheckbox.Value, type = 'reverse'; else, type = 'normal'; end
        set(gca, 'YDir',type);
    end

    Summary

    Creating a custom app toolstrip requires careful planning of the tabs, sections, controls and their layout, as well as preparation of the icons, labels and callbacks. Once you start playing with the toolstrip API, you’ll see that it’s quite easy to understand and to use. I think MathWorks did a good job in general with this API, and it’s a pity that they did not make it public or official long ago (the MCOS API discussed above existed since 2014-2015; earlier versions existed at least as far back as 2011). Comparing the changes made in the API between R2018a and R2018b shows quite minor differences, which may possibly means that the API is now considered stable, and therefore that it might well be made public in some near-term future. Still, note that this API may well change in future releases (for example, naming of the control properties that I mentioned above). It works well in R2018b, as well as in the past several Matlab releases, but this could well change in the future, so beware.

    In the following posts I will discuss advanced control customizations (icons, callbacks, collapsibility etc.), complex controls (drop-downs, pop-ups, lists, button groups, items gallery etc.) and low-level toolstrip creation and customization. As I said above, Matlab toolstrips are quite an extensive subject and so I plan to proceed slowly, with each post building on its predecessors. Stay tuned!

    In the meantime, 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-3-basic-customization/feed 21
    Matlab toolstrip – part 2 (ToolGroup App)https://undocumentedmatlab.com/blog_old/matlab-toolstrip-part-2-toolgroup-app https://undocumentedmatlab.com/blog_old/matlab-toolstrip-part-2-toolgroup-app#comments Wed, 05 Dec 2018 17:00:48 +0000 https://undocumentedmatlab.com/?p=8059 Related posts:
    1. Matlab toolstrip – part 9 (popup figures) Custom popup figures can be attached to Matlab GUI toolstrip controls. ...
    2. Figure window customizations Matlab figure windows can be customized in numerous manners using the underlying Java Frame reference. ...
    3. Builtin PopupPanel widget We can use a built-in Matlab popup-panel widget control to display lightweight popups that are attached to a figure window. ...
    4. Matlab toolstrip – part 6 (complex controls) Multiple types of customizable controls can be added to Matlab toolstrips...
    ]]>
    A while ago I posted the first of my planned miniseries on the Matlab toolstrip (ribbon). Today I will expand that post by discussing how toolstrips can be added to Matlab GUIs. This post will remain at a high-level as the previous post, with followup posts drilling into the technical details of the toolstrip components (inner packages and classes).

    We can add a Matlab toolstrip to 3 types of Matlab GUI windows:

    1. To a Java-based Matlab figure (so-called “legacy” figures, created using GUIDE or the figure function)
    2. To a container window of docked Java-based figures, typically called an “App” (marketing name) or “Tool Group” (internal technical name)
    3. To a JavaScript/HTML-based Matlab figure (so called “web” figures, created using App Designer or the uifigure function)

    Today I will show how to add a basic dynamic toolstrip to a ToolGroup (App, window type #2):

    ToolGroup with clients and dynamic toolstrip

    ToolGroup with clients and dynamic toolstrip


    Figure containers (“Tool Groups”)

    Most Matlab users are familiar with window types #1 and #3 (legacy and web-based figures), but type #2 may seem strange. In fact, it shouldn’t be: All the Matlab “Apps” and Desktop components use such a container of docked clients. For example, both the Matlab Editor and Desktop are containers of individual client windows (individual files in the Editor; Command Window, Workspace etc. in the desktop).

    Similarly, when we dock figures, they dock as client windows into a container called “Figures” (this can be controlled programmatically: see my setFigDockGroup utility on the File Exchange). This is the basis for all Matlab “Apps”, as far as I am aware (some Apps may possibly use a different GUI container, after all there are ~100 Matlab Apps and I’m not familiar with all of them). Such Apps are basically stand-alone Tool Groups (client container windows) that contain one or more docked figures, a toolstrip, and a side-panel with controls (so-called “Data Browser”).

    Note: MathWorks uses confusing terminology here, using the same term “App” for both MathWorks-created GUIs containers (that have toolstrips, Data Browser and docked figures) and also user-created utilities on the File Exchange (that do not have these). Unfortunately, MathWorks has chosen not [yet] to release to the general public its set of tools that enable creating true “Apps”, i.e. those that have a toolstrip, Data Browser and docked figures.

    Today’s post will attempt to fill this gap, by showing how we can create user Apps that have a toolstrip and docked figures. I will ignore the Data Browser today, and will describe it in a future post. Since docking figures into a standalone user-created container is a solved problem (using my setFigDockGroup utility), this post will focus on adding a toolstrip to such a container.

    A ToolGroup object (matlab.ui.internal.desktop.ToolGroup) is created either implicitly (by docking a figure into a group that has a new name), or explicitly (by invoking its constructor):

    % Create a new non-visible empty App (Tool Group)
    hToolGroup = matlab.ui.internal.desktop.ToolGroup('Toolstrip example on UndocumentedMatlab.com');

    Some things only work properly after the app is displayed, so let’s display the ToolGroup (however, note that for improved performance it is better to do whatever customizations and GUI updates that you can before the app is made visible):

    % Display the ToolGroup window
    hToolGroup.open();

    Basic empty ToolGroup (without toolstrip or clients)

    Basic empty ToolGroup (without toolstrip or clients)

    An annoying quirk with ToolGroups is that they automatically close when their reference handle is deleted from Matlab memory. The specific behavior changes depending on the contents of the container and the Matlab release, but in general it’s safest to preserve the hToolGroup variable, to prevent the window from closing, when this variable goes out of scope, when the function (in which we create the ToolGroup) returns. There are many ways to persist this variable. Here’s one alternative, in which we persist it in itself (or rather, attached to its internal Java peer control):

    % Store toolgroup reference handle so that app will stay in memory
    jToolGroup = hToolGroup.Peer;
    internal.setJavaCustomData(jToolGroup, hToolGroup);

    internal.setJavaCustomData is an undocumented Matlab function that adds a new custom property to a Java reference handle. In our case, it adds a CustomData property to the jToolGroup handle and sets its value to the Matlab hToolGroup handle. The source code for internal.setJavaCustomData is available in %matlabroot%/toolbox/shared/controllib/general/+internal/setJavaCustomData.m and is very simple: it essentially uses the old schema-based schema.prop method for adding new properties to handles. Schema is an old deprecated mechanism that is mostly replaced by the newer MCOS (Matlab Class Object System), but for some specific cases such as this it’s still very useful (the standard addprop function can add new properties to Matlab GUI handles, but not to Java reference handles).

    Finally, let’s discard the Data Browser side panel (I’ll discuss it in a separate future post):

    % Discard the Data-browser left panel
    hToolGroup.disableDataBrowser();

    Adding a toolstrip to the ToolGroup

    Now that we have the basic container ready, let’s add a toolstrip. To simplify matters in this introductory post (after all, I have still not described the internal packages and classes that make up a toolstrip), we’ll use some of the tabs used in the showcaseToolGroup example that I discussed in my previous post. You can see the relevant source code in %matlabroot%/toolbox/matlab/toolstrip/+matlab/+ui/+internal/+desktop/*.m, in case you want to jump ahead and customize your own toolstrip tabs, groups and buttons. In the code snippet below, we first create an empty TabGroup, then add toolstrip tabs into it, and finally add this TabGroup into our ToolGroup using its addTabGroup(hTabGroup) method:

    % Create a new tab group
    %hTabGroup = matlab.ui.internal.desktop.showcaseBuildTabGroup('swing');
    hTabGroup = matlab.ui.internal.toolstrip.TabGroup();
    hTab1 = matlab.ui.internal.desktop.showcaseBuildTab_Buttons('swing');
    hTabGroup.add(hTab1);
    %hTabGroup.add(matlab.ui.internal.desktop.showcaseBuildTab_Gallery());
    hTabGroup.add(matlab.ui.internal.desktop.showcaseBuildTab_Layout('swing'));
     
    % Select tab #1 (common)
    hTabGroup.SelectedTab = hTab1;
     
    % Add the tab group to the built-in toolstrip
    hToolGroup.addTabGroup(hTabGroup);

    We now have an “App” that has a toolstrip, but no clients (yet), and a hidden Data Browser side-panel:

    ToolGroup "App" with a simple toolstrip (no clients yet)

    Now let’s add some clients (docked figures):

    Adding clients (docked figures) to the ToolGroup

    There are two easy variants for adding docked figures in a ToolGroup: The easiest is to use the ToolGroup’s addFigure(hFigure) method:

    % Create a figure and dock it into the tool-group
    hFig1 = figure('Name','3D');
    surf(peaks);
    hToolGroup.addFigure(hFig1);

    The second variant enables to dock a figure that has a specific set of toolstrip tabs attached to it. These tabs will only display in the toolstrip when that particular figure has focus. We do this by creating a new TabGroup (just as we have done above), and then add the figure and TabGroup to the container using the ToolGroup’s addClientTabGroup(hFigure,hTabGroup) method:

    % Create the 2nd figure
    hFig2 = figure('Name','2D');
    plot(rand(5)); drawnow
     
    % Add a few tabs that are only relevant to this specific figure
    hTabGroup2 = matlab.ui.internal.toolstrip.TabGroup();
    hTab2 = matlab.ui.internal.desktop.showcaseBuildTab_Selections();
    hTabGroup2.add(hTab2);
    hTabGroup2.add(matlab.ui.internal.desktop.showcaseBuildTab_EditValue());
     
    % Add the figure and tabs to the ToolGroup
    hToolGroup.addClientTabGroup(hFig2, hTabGroup2);

    ToolGroup with clients and dynamic toolstrip

    ToolGroup with clients and dynamic toolstrip

    In this example, the “Selection” and “Values” toolstrip tabs only appear when the 2nd figure (“2D”) has focus. A similar behavior exists in the Matlab Desktop and Editor, where some tabs are only shown when certain clients have focus.

    Removing the View tab

    Note that the “View” toolstrip tab (which enables setting the appearance of the docked figures: layout, tab positions (top/bottom/left/right), ordering etc.) is automatically added to the toolstrip and always appears last. We can remove this View tab using the ToolGroup’s hideViewTab() method. The tab will not immediately be removed, only when the toolstrip is repainted, for example, when we switch focus between the docked figures:

    hToolGroup.hideViewTab;  % toolstrip View tab is still visible at this point
    figure(hFig1);  % change focus to hFig1 - toolstrip is repainted without View tab

    Conclusion

    It’s relatively easy to dock figures into a standalone “App” window that has a custom toolstrip, which can even be dynamically modified based on the figure which is currently in focus. Naturally, this has little benefit if we cannot customize the toolstrip components: labels, icons, control type, grouping and most importantly – callbacks. This topic deserves a dedicated post, which I plan to be the next in this miniseries. Stay tuned – hopefully the next post will not take me as long to publish as this post (I was quite busy recently)…

    ]]>
    https://undocumentedmatlab.com/blog_old/matlab-toolstrip-part-2-toolgroup-app/feed 11
    Toolbar button labelshttps://undocumentedmatlab.com/blog_old/toolbar-button-labels https://undocumentedmatlab.com/blog_old/toolbar-button-labels#respond Mon, 08 Jan 2018 17:34:17 +0000 https://undocumentedmatlab.com/?p=7270 Related posts:
    1. Customizing figure toolbar background Setting the figure toolbar's background color can easily be done using just a tiny bit of Java magic powder. This article explains how. ...
    2. Builtin PopupPanel widget We can use a built-in Matlab popup-panel widget control to display lightweight popups that are attached to a figure window. ...
    3. Matlab toolstrip – part 9 (popup figures) Custom popup figures can be attached to Matlab GUI toolstrip controls. ...
    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....
    ]]>
    I was recently asked by a client to add a few buttons labeled “1”-“4” to a GUI toolbar. I thought: How hard could that be? Simply get the toolbar’s handle from the figure, then use the builtin uipushtool function to add a new button, specifying the label in the String property, right?

    Labeled toolbar buttons

    Well, not so fast it seems:

    hToolbar = findall(hFig, 'tag','FigureToolBar');  % get the figure's toolbar handle
    uipushtool(hToolbar, 'String','1');               % add a pushbutton to the toolbar
    Error using uipushtool
    There is no String property on the PushTool class. 

    Apparently, for some unknown reason, standard Matlab only enables us to set the icon (CData) of a toolbar control, but not a text label.

    Once again, Java to the rescue:

    We first get the Java toolbar reference handle, then add the button in standard Matlab (using uipushtool, uitoggletool and their kin). We can now access the Java toolbar’s last component, relying on the fact that Matlab always adds new buttons at the end of the toolbar. Note that we need to use a short drawnow to ensure that the toolbar is fully re-rendered, otherwise we’d get an invalid Java handle. Finally, once we have this reference handle to the underlying Java button component, we can set and customize its label text and appearance (font face, border, size, alignment etc.):

    hToolbar = findall(hFig, 'tag','FigureToolBar');     % get the figure's toolbar handle
    jToolbar = hToolbar.JavaContainer.getComponentPeer;  % get the toolbar's Java handle
    for buttonIdx = 1 : 4
        % First create the toolbar button using standard Matlab code
        label = num2str(buttonIdx);  % create a string label
        uipushtool(hToolbar, 'ClickedCallback',{@myCallback,analysisIdx}, 'TooltipString',['Run analysis #' label]);
     
        % Get the Java reference handle to the newly-created button
        drawnow; pause(0.01);  % allow the GUI time to re-render the toolbar
        jButton = jToolbar.getComponent(jToolbar.getComponentCount-1);
     
        % Set the button's label
        jButton.setText(label)
    end

    The standard Matlab toolbar button size (23×23 pixels) is too small to display more than a few characters. To display a longer label, we need to widen the button:

    % Make the button wider than the standard 23 pixels
    newSize = java.awt.Dimension(50, jButton.getHeight);
    jButton.setMaximumSize(newSize)
    jButton.setPreferredSize(newSize)
    jButton.setSize(newSize)

    Using a text label does not prevent us from also displaying an icon: In addition to the text label, we can also display a standard icon (by setting the button’s CData property in standard Matlab). This icon will be displayed to the left of the text label. You can widen the button, as shown in the code snippet above, to make space for both the icon and the label. If you want to move the label to a different location relative to the icon, simply modify the Java component’s HorizontalTextPosition property:

    jButton.setHorizontalTextPosition(jButton.RIGHT);   % label right of icon (=default)
    jButton.setHorizontalTextPosition(jButton.CENTER);  % label on top of icon
    jButton.setHorizontalTextPosition(jButton.LEFT);    % label left of icon

    In summary, here’s the code snippet that generated the screenshot above:

    % Get the Matlab & Java handles to the figure's toolbar
    hToolbar = findall(hFig, 'tag','FigureToolBar');     % get the figure's toolbar handle
    jToolbar = hToolbar.JavaContainer.getComponentPeer;  % get the toolbar's Java handle
     
    % Button #1: label only, no icon, 23x23 pixels
    h1 = uipushtool(hToolbar);
    drawnow; pause(0.01);
    jButton = jToolbar.getComponent(jToolbar.getComponentCount-1);
    jButton.setText('1')
     
    % Create the icon CData from an icon file
    graphIcon = fullfile(matlabroot,'/toolbox/matlab/icons/plotpicker-plot.gif');
    [graphImg,map] = imread(graphIcon);
    map(map(:,1)+map(:,2)+map(:,3)==3) = NaN;  % Convert white pixels => transparent background
    cdata = ind2rgb(graphImg,map);
     
    % Button #2: label centered on top of icon, 23x23 pixels
    h2 = uipushtool(hToolbar, 'CData',cdata);
    drawnow; pause(0.01);
    jButton = jToolbar.getComponent(jToolbar.getComponentCount-1);
    jButton.setText('2')
    jButton.setHorizontalTextPosition(jButton.CENTER)
     
    % Button #3: label on right of icon, 50x23 pixels
    h3 = uipushtool(hToolbar, 'CData',cdata);
    drawnow; pause(0.01);
    jButton = jToolbar.getComponent(jToolbar.getComponentCount-1);
    jButton.setText('3...')
    d = java.awt.Dimension(50, jButton.getHeight);
    jButton.setMaximumSize(d); jButton.setPreferredSize(d); jButton.setSize(d)
     
    % Button #4: label on left of icon, 70x23 pixels
    h4 = uipushtool(hToolbar, 'CData',cdata);
    drawnow; pause(0.01);
    jButton = jToolbar.getComponent(jToolbar.getComponentCount-1);
    jButton.setText('and 4:')
    jButton.setHorizontalTextPosition(jButton.LEFT)
    d = java.awt.Dimension(70, jButton.getHeight);
    jButton.setMaximumSize(d); jButton.setPreferredSize(d); jButton.setSize(d)

    Many additional toolbar customizations can be found here and in my book “Undocumented Secrets of MATLAB-Java Programming“. If you’d like me to design a professional-looking GUI for you, please contact me.

    Caveat emptor: all this only works with the regular Java-based GUI figures, not web-based (“App-Designer”) uifigures.

    ]]>
    https://undocumentedmatlab.com/blog_old/toolbar-button-labels/feed 0
    PlotEdit context-menu customizationhttps://undocumentedmatlab.com/blog_old/plotedit-context-menu-customization https://undocumentedmatlab.com/blog_old/plotedit-context-menu-customization#respond Wed, 13 Dec 2017 12:57:14 +0000 https://undocumentedmatlab.com/?p=7236 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. Tab panels – uitab and relatives This article describes several undocumented Matlab functions that support tab-panels...
    4. Graphic sizing in Matlab R2015b Matlab release R2015b's new "DPI-aware" nature broke some important functionality. Here's what can be done... ...
    ]]>
    Last week, a Matlab user asked whether it is possible to customize the context (right-click) menu that is presented in plot-edit mode. This menu is displayed by clicking the plot-edit (arrow) icon on the standard Matlab figure toolbar, then right-clicking any graphic/GUI element in the figure. Unfortunately, it seems that this context menu is only created the first time that a user right-clicks in plot-edit mode – it is not accessible before then, and so it seems impossible to customize the menu before it is presented to the user the first time.

    Customized plot-edit context-menu

    Customized plot-edit context-menu

    A few workarounds were suggested to the original poster and you are most welcome to review them. There is also some discussion about the technical reasons that none of the “standard” ways of finding and modifying menu items fail in this case.

    In today’s post I wish to repost my solution, in the hope that it might help other users in similar cases.

    My solution is basically this:

    1. First, enter plot-edit mode programmatically using the plotedit function
    2. Next, move the mouse to the screen location of the relevant figure component (e.g. axes). This can be done in several different ways (the root object’s PointerLocation property, the moveptr function, or java.awt.Robot.mouseMove() method).
    3. Next, automate a mouse right-click using the built in java.awt.Robot class (as discussed in this blog back in 2010)
    4. Next, locate the relevant context-menu item and modify its label, callback or any of its other properties
    5. Next, dismiss the context-menu by simulating a follow-on right-click using the same Robot object
    6. Finally, exit plot-edit mode and return the mouse pointer to its original location
    % Create an initial figure / axes for demostration purpose
    fig = figure('MenuBar','none','Toolbar','figure');
    plot(1:5); drawnow; 
     
    % Enter plot-edit mode temporarily
    plotedit(fig,'on'); drawnow
     
    % Preserve the current mouse pointer location
    oldPos = get(0,'PointerLocation');
     
    % Move the mouse pointer to within the axes boundary
    % ref: https://undocumentedmatlab.com/blog/undocumented-mouse-pointer-functions
    figPos = getpixelposition(fig);   % figure position
    axPos  = getpixelposition(gca,1); % axes position
    figure(fig);  % ensure that the figure is in focus
    newPos = figPos(1:2) + axPos(1:2) + axPos(3:4)/4;  % new pointer position
    set(0,'PointerLocation',newPos);  % alternatives: moveptr(), java.awt.Robot.mouseMove()
     
    % Simulate a right-click using Java robot
    % ref: https://undocumentedmatlab.com/blog/gui-automation-robot
    robot = java.awt.Robot;
    robot.mousePress  (java.awt.event.InputEvent.BUTTON3_MASK); pause(0.1)
    robot.mouseRelease(java.awt.event.InputEvent.BUTTON3_MASK); pause(0.1)
     
    % Modify the <clear-axes> menu item
    hMenuItem = findall(fig,'Label','Clear Axes');
    if ~isempty(hMenuItem)
       label = '<html><b><i><font color="blue">Undocumented Matlab';
       callback = 'web(''https://undocumentedmatlab.com'',''-browser'');';
       set(hMenuItem, 'Label',label, 'Callback',callback);
    end
     
    % Hide the context menu by simulating a left-click slightly offset
    set(0,'PointerLocation',newPos+[-2,2]);  % 2 pixels up-and-left
    pause(0.1)
    robot.mousePress  (java.awt.event.InputEvent.BUTTON1_MASK); pause(0.1)
    robot.mouseRelease(java.awt.event.InputEvent.BUTTON1_MASK); pause(0.1)
     
    % Exit plot-edit mode
    plotedit(fig,'off'); drawnow
     
    % Restore the mouse pointer to its previous location
    set(0,'PointerLocation',oldPos);

    In this code, I sprinkled a few pauses at several locations, to ensure that everything has time to fully render. Different pause values, or perhaps no pause at all, may be needed on your specific system.

    Modifying the default context-menu shown in plot-edit mode may perhaps be an uncommon use-case. But the technique that I demonstrated above – of using a combination of Matlab and Java Robot commands to automate a certain animation – can well be used in many other use-cases where we cannot easily access the underlying code. For example, when the internal code is encoded/encrypted, or when a certain functionality (such as the plot-edit context-menu) is created on-the-fly.

    If you have encountered a similar use-case where such automated animations can be used effectively, please add a comment below.

    ]]>
    https://undocumentedmatlab.com/blog_old/plotedit-context-menu-customization/feed 0
    Builtin PopupPanel widgethttps://undocumentedmatlab.com/blog_old/builtin-popuppanel-widget https://undocumentedmatlab.com/blog_old/builtin-popuppanel-widget#comments Wed, 06 Dec 2017 16:00:34 +0000 https://undocumentedmatlab.com/?p=7188 Related posts:
    1. Toolbar button labels GUI toolbar button labels can easily be set and customized using underlying Java components. ...
    2. Matlab toolstrip – part 9 (popup figures) Custom popup figures can be attached to Matlab GUI toolstrip controls. ...
    3. Uitable sorting Matlab's uitables can be sortable using simple undocumented features...
    4. Frameless (undecorated) figure windows Matlab figure windows can be made undecorated (borderless, title-less). ...
    ]]>
    8 years ago I blogged about Matlab’s builtin HelpPopup widget. This control is used by Matlab to display popup-windows with help documentation, but can also be used by users to display custom lightweight popups that contain HTML-capable text and even URLs of entire webpages. Today I’d like to highlight another builtin Matlab widget, ctrluis.PopupPanel, which can be used to display rich contents in a lightweight popup box attached to a specific Matlab figure:
    Matlab's builtin PopupPanel widget

    Matlab's builtin PopupPanel widget

    As you can see, this popup-panel displays richly-formatted contents, having either an opaque or transparent background, with vertical scrollbars being applied automatically. The popup pane is not limited to displaying text messages – in fact, it can display any Java GUI container (e.g. a settings panel). This popup-panel is similar in concept to the HelpPopup widget, and yet much more powerful in several aspects.

    Creating the popup panel

    Creating a PopupPanel is very simple:

    % Create the popup-panel in the specified figure
    hPopupPanel = ctrluis.PopupPanel(gcf);  % use gcf or any figure handle
    hPopupPanel.setPosition([.1,.1,.8,.8]);  % set panel position (normalized units)
     
    % Alternative #1: set popup-panel's contents to some HTML-formatted message
    % note: createMessageTextPane() has optional input args FontName (arg #2), FontSize (#3)
    jPanel = ctrluis.PopupPanel.createMessageTextPane('testing <b><i>123</i></b> ...')
    hPopupPanel.setPanel(jPanel);
     
    % Alternative #2: set popup-panel's contents to a webpage URL
    url = 'https://undocumentedmatlab.com/files/sample-webpage.html';
    jPanel = javaObjectEDT(javax.swing.JEditorPane(url));
    hPopupPanel.setPanel(jPanel);

    The entire contents are embedded within a scroll-box (which is a com.mathworks.widgets.LightScrollPane object) whose scrollbars automatically appear as-needed, so we don’t need to worry about the contents fitting the allocated space.

    To display custom GUI controls in the popup, we can simply contain those GUI controls in a Java container (e.g., a JPanel) and then do hPopupPanel.setPanel(jPanel). This functionality can be used to create unobtrusive settings panels, input dialogs etc.

    The nice thing about the popup widget is that it is attached to the figure, and yet is not assigned a heavyweight window (so it does not appear in the OS task-bar). The popup moves along with the figure when the figure is moved, and is automatically disposed when the figure is closed.

    A few caveats about the ctrluis.PopupPanel control:

    • The widget’s parent is expected to be a figure that has pixel units. If it doesn’t, the internal computations of ctrluis.PopupPanel croak.
    • The widget’s position is specified in normalized units (default: [0,0,1,1]). This normalized position is only used during widget creation: after creation, if you resize the figure the popup-panel’s position remains unchanged. To modify/update the position of the popup-panel programmatically, use hPopupPanel.setPosition(newPosition). Alternatively, update the control’s Position property and then call hPopupPanel.layout() (there is no need to call layout when you use setPosition).
    • This functionality is only available for Java-based figures, not the new web-based (AppDesigner) uifigures.

    Popup panel customizations

    We can open/close the popup panel by clicking on its icon, as shown in the screenshots above, or programmatically using the control’s methods:

    % Programmatically open/close the popup-panel
    hPopupPanel.showPanel;
    hPopupPanel.hidePanel;
     
    % Show/hide entire popup-panel widget (including its icon)
    hPopupPanel.setVisible(true);   % or .setVisible(1) or .Visible=1
    hPopupPanel.setVisible(false);  % or .setVisible(0) or .Visible=0

    To set a transparent background to the popup-panel (as shown in the screenshots above), we need to unset the opacity of the displayed panel and several of its direct parents:

    % Set a transparent popup-panel background
    for idx = 1 : 6
       jPanel.setOpaque(false);  % true=opaque, false=transparent
       jPanel = jPanel.getParent;
    end
    jPanel.repaint

    Note that in the screenshots above, the panel’s background is made transparent, but the contained text and image remain opaque. Your displayed images can of course contain transparency and animation, if this is supported by the image format (for example, GIF).

    iptui.internal.utilities.addMessagePane

    ctrluis.PopupPanel is used internally by iptui.internal.utilities.addMessagePane(hFig,message) in order to display a minimizable single-line message panel at the top of a specified figure:

    hPopupPanel = iptui.internal.utilities.addMessagePane(gcf, 'testing <b>123</b> ...');  % note the HTML formatting

    The function updates the message panel’s position whenever the figure’s size is modified (by trapping the figure’s SizeChangedFcn), to ensure that the panel is always attached to the top of the figure and spans the full figure width. This is a simple function so I encourage you to take a look at its code (%matlabroot%/toolbox/images/imuitools/+iptui/+internal/+utilities/addMessagePane.m) – note that this might require the Image Processing Toolbox (I’m not sure).

    Matlab's builtin iptui.internal.utilities.addMessagePane

    Matlab's builtin iptui.internal.utilities.addMessagePane

    Professional assistance anyone?

    As shown by this and many other posts on this site, a polished interface and functionality is often composed of small professional touches, many of which are not exposed in the official Matlab documentation for various reasons. So if you need top-quality professional appearance/functionality in your Matlab program, or maybe just a Matlab program that is dependable, robust and highly-performant, consider employing my consulting services.

    ]]>
    https://undocumentedmatlab.com/blog_old/builtin-popuppanel-widget/feed 1
    Matlab GUI training seminars – Zurich, 29-30 August 2017https://undocumentedmatlab.com/blog_old/matlab-gui-training-seminars-zurich-29-30-august-2017 https://undocumentedmatlab.com/blog_old/matlab-gui-training-seminars-zurich-29-30-august-2017#respond Fri, 04 Aug 2017 09:37:52 +0000 https://undocumentedmatlab.com/?p=6992 Related posts:
    1. 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...
    2. 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....
    3. 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....
    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....
    ]]>
    Advanced Matlab training, Zurich 29-30 August 2017
    Advanced Matlab training courses/seminars will be presented by me (Yair) in Zürich, Switzerland on 29-30 August, 2017:

    • August 29 (full day) – Interactive Matlab GUI
    • August 30 (full day) – Advanced Matlab GUI

    The seminars are targeted at Matlab users who wish to improve their program’s usability and professional appearance. Basic familiarity with the Matlab environment and coding/programming is assumed. The courses will present a mix of both documented and undocumented aspects, which is not available anywhere else. The curriculum is listed below.

    This is a unique opportunity to enhance your Matlab coding skills and improve your program’s usability in a couple of days.

    If you are interested in either or both of these seminars, please Email me (altmany at gmail dot com).

    I can also schedule a dedicated visit to your location, for onsite Matlab training customized to your organization’s specific needs. Additional information can be found on my Training page.

    Around the time of the training, I will be traveling to various locations around Switzerland. If you wish to meet me in person to discuss how I could bring value to your project, then please email me (altmany at gmail):

    • Geneva: Aug 22 – 27
    • Bern: Aug 27 – 28
    • Zürich: Aug 28 – 30
    • Stuttgart: Aug 30 – 31
    • Basel: Sep 1 – 3

     Email me


    Interactive Matlab GUI – 29 August, 2017

    1. Introduction to Matlab Graphical User Interfaces (GUI)
      • Design principles and best practices
      • Matlab GUI alternatives
      • Typical evolution of Matlab GUI developers
    2. GUIDE – MATLAB’s GUI Design Editor
      • Using GUIDE to design a custom GUI
      • Available built-in MATLAB uicontrols
      • Customizing uicontrols
      • Important figure and uicontrol properties
      • GUIDE utility windows
      • The GUIDE-generated file-duo
    3. Customizing GUI appearance and behavior
      • Programmatic GUI creation and control
      • GUIDE vs. m-programming
      • Attaching callback functionality to GUI components
      • Sharing data between GUI components
      • The handles data struct
      • Using handle visibility
      • Position, size and units
      • Formatting GUI using HTML
    4. Uitable
      • Displaying data in a MATLAB GUI uitable
      • Controlling column data type
      • Customizing uitable appearance
      • Reading uitable data
      • Uitable callbacks
      • Additional customizations using Java
    5. Matlab’s new App Designer and web-based GUI
      • App Designer environment, widgets and code
      • The web-based future of Matlab GUI and assumed roadmap
      • App Designer vs. GUIDE – pros and cons comparison
    6. Performance and interactivity considerations
      • Speeding up the initial GUI generation
      • Improving GUI responsiveness
      • Actual vs. perceived performance
      • Continuous interface feedback
      • Avoiding common performance pitfalls
      • Tradeoff considerations

    At the end of this seminar, you will have learned how to:

    • apply GUI design principles in Matlab
    • create simple Matlab GUIs
    • manipulate and customize graphs, images and GUI components
    • display Matlab data in a variety of GUI manners, including data tables
    • decide between using GUIDE, App Designer and/or programmatic GUI
    • understand tradeoffs in design and run-time performance
    • comprehend performance implications, to improve GUI speed and responsiveness

    Advanced Matlab GUI – 30 August, 2017

    1. Advanced topics in Matlab GUI
      • GUI callback interrupts and re-entrancy
      • GUI units and resizing
      • Advanced HTML formatting
      • Using hidden (undocumented) properties
      • Listening to action and property-change events
      • Uitab, uitree, uiundo and other uitools
    2. Customizing the figure window
      • Creating and customizing the figure’s main menu
      • Creating and using context menus
      • Creating and customizing figure toolbars
    3. Using Java with Matlab GUI
      • Matlab and Java Swing
      • Integrating Java controls in Matlab GUI
      • Handling Java events as Matlab callbacks
      • Integrating built-in Matlab controls/widgets
      • Integrating JIDE’s advanced features and professional controls
      • Integrating 3rd-party Java components: charts/graphs/widgets/reports
    4. Advanced Matlab-Java GUI
      • Customizing standard Matlab uicontrols
      • Figure-level customization (maximize/minimize, disable etc.)
      • Containers and position – Matlab vs. Java
      • Compatibility aspects and trade-offs
      • Safe programming with Java in Matlab
      • Java’s EDT and timing considerations
      • Deployment (compiler) aspects

    At the end of this seminar, you will have learned how to:

    • customize the figure toolbar and main menu
    • use HTML to format GUI appearance
    • integrate Java controls in Matlab GUI
    • customize your Matlab GUI to a degree that you never knew was possible
    • create a modern-looking professional GUI in Matlab
    ]]>
    https://undocumentedmatlab.com/blog_old/matlab-gui-training-seminars-zurich-29-30-august-2017/feed 0
    Figure window customizationshttps://undocumentedmatlab.com/blog_old/figure-window-customizations https://undocumentedmatlab.com/blog_old/figure-window-customizations#respond Wed, 01 Jun 2016 08:00:11 +0000 https://undocumentedmatlab.com/?p=6439 Related posts:
    1. Minimize/maximize figure window Matlab figure windows can easily be maximized, minimized and restored using a bit of undocumented magic powder...
    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. Frameless (undecorated) figure windows Matlab figure windows can be made undecorated (borderless, title-less). ...
    ]]>
    A friend recently asked me, in light of my guesstimate that Java-based Matlab figures will be replaced by web-based figures sometime around 2018-2020, whether there are any “killer features” that make it worthwhile to use undocumented Java-based tricks today, despite the fact that they will probably break in 2-5 years. In my opinion, there are many such features; today I will focus on just a subset of them – those features that relate to the entire figure window.

    Over the years I wrote many articles here about figure-level customizations, as well as an entire chapter in my Matlab-Java programming book. So today’s post will be a high-level overview, and users who are interested in any specific topic can visit the referenced links for the implementation details.

    An undecorated Matlab figure window - one of many possible figure-level customizations
    An undecorated Matlab figure window – one of many possible figure-level customizations

    JavaFrame

    JavaFrame is an undocumented hidden property of the figure handle that provides access to the underlying Java window (JFrame) peer object’s reference. Since R2008a, a warning is issued whenever we retrieve this property:

    >> jFrame = get(gcf,'JavaFrame');
    Warning: figure JavaFrame property will be obsoleted in a future release.
    For more information see the JavaFrame resource on the MathWorks web site.
    (Type "warning off MATLAB:HandleGraphics:ObsoletedProperty:JavaFrame" to suppress this warning.) 
    

    Until HG2 (R2014b+) we could suppress the warning by simply wrapping the figure handle within a handle() call, as explained here. Since R2014b we need to use the warning function to do this:

    warning('off', 'MATLAB:HandleGraphics:ObsoletedProperty:JavaFrame');

    We can do several things directly with the JavaFrame‘s properties and methods, including:

    • Maximize/minimize/restore the window, via the properties Maximized/Minimized (which accept and return a boolean (logical) value), or the corresponding methods jFrame.isMaximized(), isMinimized(), setMaximized(flag), setMinimized(flag). details
    • Modify the container to which the figure will be docked. By default this is the “Figures” container, but this can be changed to any user-specified container, or even to the “Editor”, using the GroupName property or its associated methods. See the related setFigDockGroup utility that I posted on the Matlab File exchange.
    • Remove the top separator line between the toolbar and the content-pane, to blend them together, via the jFrame.showTopSeparator(flag) method.
    • Retrieve a direct Java reference to the Matlab Desktop and the figure’s internal containers via the Desktop and FigurePanelContainer properties, respectively (we can also get those references by other means).
    • Retrieve a direct Java reference to the containing JFrame (Java window), as discussed below
    • A few other features that I will not discuss here

    MathWorks have set up a dedicated webpage where you can specify how you are using JavaFrame and why it is important for you: http://www.mathworks.com/javaframe. I encourage you to use this webpage to tell MathWorks which features are important for you. This will help them to decide which functionality should be added to the new web-based figures.

    JFrame window

    The JavaFrame handle enables direct retrieval of the containing Java JFrame (window) reference, using several alternatives. Here are two of these alternatives (there are others):

    % Alternative #1
    >> jWindow = jFrame.getFigurePanelContainer.getTopLevelAncestor
    jWindow = 
    com.mathworks.hg.peer.FigureFrameProxy$FigureFrame[fClientProxyFrame,72,62,576x507,...]
     
    % Alternative #2
    try
        jClient = jFrame.fFigureClient;  % This works up to R2011a
    catch
        try
            jClient = jFrame.fHG1Client;  % This works from R2008b-R2014a
        catch
            jClient = jFrame.fHG2Client;  % This works from R2014b and up
        end
    end
    jWindow = jClient.getWindow;

    Customized menu items Customized menu items
    Integrated figure status bar

    Customized menu items (top) and figure status bar (bottom)

    With the retrieved jWindow reference, we can do several additional interesting things:

    • Enable/disable the entire figure in a single go (details)
    • Remove/restore the window frame (borders and title bar), otherwise known as an “undecorated window” (details)
    • Set the figure window to be “Always-On-Top”, i.e. not occluded by any other window, via the AlwaysOnTop property, or the corresponding jWindow.isAlwaysOnTop(), setAlwaysOnTop(flag) methods.
    • Make the figure window fully or partially transparent (details). Note: this fails on R2013b/Java7 and higher due to a change in the way that transparency works in Java 7 compared to earlier releases; in other words blame Oracle’s Java, not MathWorks’ Matlab….
    • Blur/restore the figure window (details). This too works only up to R2013a.
    • Detect and handle window-level focus gain/loss events (details), as well as window-level mouse events (enter/exit/hover etc. – details).
    • Customize the figure’s menu bar – dynamic behavior, tooltips, highlights, keyboard shortcuts/accelerators, font colors/styles, callbacks, icons etc. (details1, details2)
    • Control figure docking in compiled (deployed) applications (details1, details2)
    • Display an integral figure status-bar with text and GUI controls (details1, details2).
    • A few other features that I will not discuss here

    As you can see, there are numerous very interesting customizations that can be done to Matlab figures which rely on the undocumented implementation. Here are a couple of usage examples that you can easily adapt (follow the links above for additional details and usage examples):

    jWindow.setEnabled(false);     % disable entire figure [true/false]
    jWindow.setMinimized(true);    % minimize window [true/false]
    jWindow.setMaximized(true);    % maximize window [true/false]
    jWindow.setAlwaysOnTop(true);  % set to be always on top [true/false]
     
    % Set a Matlab callback function to a window focus-gain event
    hjWindow = handle(jWindow, 'CallbackProperties');
    hjWindow.FocusGainedCallback = @myCallbackFunc;

    In addition to the Java-based features above, some functionalities can also be achieved via direct OS manipulations, for example using Jan Simon’s great WindowAPI utility (Windows-only), although I typically prefer using the Java approach since it is cross-platform compatible.

    Using all these features is super-easy, so there is not really a question of code complexity or technical risk – the main question is whether to accept the risk that the associated code will stop working when Matlab figures will eventually become web-based.

    So is it worth the risk?

    This is an excellent question. I contend that the answer depends on the specific use-case. In one project you may decide that it is indeed worth-while to use these undocumented features today, whereas in another GUI you may decide that it is not.

    It might make sense to use the features above in any of the following circumstances:

    • If you need any of the features in your Matlab GUI today. In this case, you really have no alternative other than to use these features, since there is no documented way to achieve the required functionality.
    • If you do not plan to upgrade your Matlab release soon, or at least after the Java-based figures are discontinued in a few years. The commercial Matlab license is perpetual, enabling users to enjoy these features for as long as they continue using this Matlab release.
    • If you are compiling your Matlab program using the Matlab Compiler or Coder toolboxes. In such cases, the executable will remain static, until such time (if ever) that you decide to recompile it using a newer Matlab release. Users of the compiled code could continue to use the compiled undocumented features well into the future, for as long as their computers keep running. In such cases, we are not concerned with release compatibility issues.
    • If you accept the risk that some recoding may be necessary in the future, or that some functionality will degrade, for the added benefit that they provide your GUIs today.
    • If you are willing to code without MathWorks’ official support and endorsement, and accept the fact that they will not fix any internal bugs that you may discover which is related to these features.
    • If you wish to present a professional-grade GUI today, and worry about potential incompatibilities only if and when they eventually arrive, sometime in the future.

    Here’s another twist to consider: do not take it for granted that when web-based uifigures replace Java-based figures all the documented functionality will work as-is on the new uifigures just as they have on the old figures. In fact, I personally believe that we will need to extensively modify our GUI code to make it compatible with the new uifigures. In other words, avoiding the undocumented hacks above will probably not save us from the need to recode (or at least adapt) our GUI, it will just reduce the necessary work somewhat. We encountered a similar situation with the graphics hacks that I exposed over the years: many people avoided them in the fear that they might someday break; then when R2014b came and HG2 graphics replaced HG1, it turned out that many of these supposedly risky hacks continued working in HG2 (examples: LooseInset, YLimInclude) whereas quite a bit of standard fully-documented Matlab functionality was broken and required some recoding. I believe that the lessons from the HG2 migration were well studied and assimilated by MathWorks, but realistically speaking we should not expect a 100% full-proof transition to uifigures.

    Still, accepting the risk does not mean that we should bury our head in the sand. Whenever using any undocumented feature in your code, I strongly suggest to use defensive coding practices, such as wrapping your code within try-catch blocks. This way, even if the feature is removed in R2020a (or whenever), the program will still run, albeit with somewhat diminished functionality, or in other words, graceful degradation. For example:

    try
        jFrame = get(hFig, 'JavaFrame');
        jFrame.setMaximized(true);
    catch
        oldUnits = get(hFig, 'Units');
        set(hFig, 'Units','norm', 'Pos',[0,0,1,1]);
        set(hFig, 'Units',oldUnits);
    end

    Once again, I urge you to visit http://www.mathworks.com/javaframe and tell MathWorks which of the above features are important for you. The more users tell MathWorks that they depend on a specific feature, the more would MathWorks be likely to invest R&D efforts in enabling it in the future web-based figures.

    ]]>
    https://undocumentedmatlab.com/blog_old/figure-window-customizations/feed 0
    Figure keypress modifiershttps://undocumentedmatlab.com/blog_old/figure-keypress-modifiers https://undocumentedmatlab.com/blog_old/figure-keypress-modifiers#comments Wed, 04 Nov 2015 21:19:59 +0000 https://undocumentedmatlab.com/?p=6059 Related posts:
    1. Matlab toolstrip – part 4 (control customization) Matlab toolstrip components (controls) can be customized in various ways, including user-defined callbacks. ...
    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. Customizing print setup Matlab figures print-setup can be customized to automatically prepare the figure for printing in a specific configuration...
    4. Minimize/maximize figure window Matlab figure windows can easily be maximized, minimized and restored using a bit of undocumented magic powder...
    ]]>
    Matlab figures have a documented property called SelectionType that returns information about keypress modifiers such as or that were pressed during mouse clicks. Using this property has several drawbacks IMHO:

    • The reported SelectionType value is 'extend' for shift-clicks and 'alt' for ctrl-clicks, not very intuitive.
    • There is no support for alt-clicks, which are reported as regular ('normal') mouse clicks. In fact, 'alt' is reported for ctrl-clicks rather than for alt-clicks, which is very confusing.
    • There is no support for modifier combinations such as ctrl+shift-click. These again are reported as regular ('normal') mouse clicks.
    • SelectionType is only updated for mouse clicks, not for keyboard clicks. This again is very confusing. To extract the keypress modifier for key-click events we need to get the Modifier property of the key-press event, and this returns a cell-array of strings (e.g., {'shift','control','alt'}). Note that in this case, unlike SelectionType, the modifier names are as expected, alt-clicks is recognised and so are modifier combinations.
    % Documented: we need to get the modifier data in two different manners
    set(gcf, 'WindowButtonDownFcn', @(h,e) disp(get(gcf,'SelectionType')));  % mouse clicks: displays a single string: 'normal','alt','extend' or 'open'
    set(gcf, 'WindowKeyPressFcn',   @(h,e) disp(e.Modifier));  % keyboard clicks: displays a cell-array of strings, e.g. {'shift','control','alt'}

    The inconsistency between the functionality for mouse and keyboard clicks, and the limitations of the SelectionType property, are striking and most annoying. Some might say that it’s been like this for the past 2 decades so Matlab users have probably gotten used to it by now. But I must admit that after over 2 decades with Matlab I still need to refer to the documentation to figure out the correct behavior. Maybe that’s because I’m getting old, or maybe it means that the behavior is indeed not as intuitive as one could hope for.

    For this reason, I was very happy to discover several years ago that there was a much simpler, easier and consistent solution, although (alas) undocumented. The trick is to simply query the undocumented hidden figure property CurrentModifier: CurrentModifier is updated during both mouse and keyboard clicks, in the same consistent manner, in both cases returning the same cell-array of strings as the Modifier property of the standard key-press event:

    % Undocumented: the following displays a cell-array of strings having a consistent format, e.g. {'shift','control','alt'}
    set(gcf, 'WindowButtonDownFcn', @(h,e) disp(get(gcf,'CurrentModifier')));  % mouse clicks
    set(gcf, 'WindowKeyPressFcn',   @(h,e) disp(get(gcf,'CurrentModifier')));  % keyboard clicks

    Checking whether any modifier was pressed becomes trivial:

    modifiers = get(gcf,'CurrentModifier');
    wasShiftPressed = ismember('shift',   modifiers);  % true/false
    wasCtrlPressed  = ismember('control', modifiers);  % true/false
    wasAltPressed   = ismember('alt',     modifiers);  % true/false

    Hurrah for simplicity and consistency!

    Note that despite the fact that CurrentModifier is hidden and undocumented, it has existed as-is for many years, and even survived (unchanged) the major transition from HG1 to HG2 in R2014b. This has to mean that MathWorks recognized the importance of CurrentModifier and took the deliberate decision (and associate dev effort) to preserve it. So why wasn’t this useful property made documented ages ago, or at the very least at the HG2 transition point? I don’t have a good answer to this riddle.

    ]]>
    https://undocumentedmatlab.com/blog_old/figure-keypress-modifiers/feed 6
    Capturing print eventshttps://undocumentedmatlab.com/blog_old/capturing-print-events https://undocumentedmatlab.com/blog_old/capturing-print-events#comments Wed, 08 Jul 2015 18:00:30 +0000 https://undocumentedmatlab.com/?p=5909 Related posts:
    1. Figure keypress modifiers The figure's CurrentModifier property provides a simple and consistent way to retrieve keypress modifiers: alt-, control- and shift-clicks. ...
    2. UDD Properties UDD provides a very convenient way to add customizable properties to existing Matlab object handles...
    3. Docking figures in compiled applications Figures in compiled applications cannot officially be docked since R2008a, but this can be done using a simple undocumented trick....
    4. Customizing figure toolbar background Setting the figure toolbar's background color can easily be done using just a tiny bit of Java magic powder. This article explains how. ...
    ]]>
    As a followup to my recent post on capturing and using HG2’s new graphic events, I would like to welcome back guest blogger Robert Cumming, who developed a commercial Matlab GUI framework. Today, Robert will highlight an unusual use of event listeners to enable print output customizations by tapping into print-related events.

    One of my toolbox clients wanted to ensure that every print-out, of any Matlab GUI, would contain a datestamp footer and a project id header.

    Initially I thought this would be a simple task, since the GUI framework already has saveAs and copyToClipboard methods that users could utilize. Moreover, as Yair has shown some years ago, we can easily adapt the standard callbacks associated with the Matlab figure toolbar’s <Print> button and the menu-bar’s Print action. We can even customize the standard print setup. However, all this does not help when directly invoking printout commands from the Matlab command line or from within the user program, for example:

    % Create the GUI
    [x,y,z] = peaks(75); 
    surf(x,y,z);
     
    % printout via print() or export_fig
    print(gcf, .... )
    export_fig filename  % see https://undocumentedmatlab.com/blog/export_fig

    Printout with the expected header and footer stamps

    Printout with the expected header and footer stamps


    This initially posed a bit of a challenge – how could I capture the print event?

    The key to solving this was using events in a different way. Rather than listen for a print event, we listen for something that print interacts with in the figure window. This will solve the problem for both print and export_fig, since export_fig uses print internally.

    We can listen to get and set events on many Matlab properties. In this instance we can trap get events on a figure’s PaperPositioMode, or PaperSize property. print, saveas and export_fig all access these properties before doing the actual printing, so by trapping the event we can run our own function before the printing is done. For example:

    classdef PrintListenerDemo
      properties
        referenceNo = 'R1234-56'
      end
     
      methods (Access=public)
        function obj = PrintListenerDemo
          hFig = figure;
          [x,y,z] = peaks(75);
          surf ( x, y, z );
     
          % add listener on event to prepare the figure for printing
          addlistener ( hFig, 'PaperPositionMode', 'PreGet', @obj.Prep );
     
          % Testing only:
          evalin ( 'base', 'print ( gcf, ''-dmeta'' )' );  % simulate user action in command-line
          print(hFig,'-dmeta');    % simulate programmatic printout
        end
     
        function Prep(obj, hFig, varargin)
          disp ( 'running function in preparation for printing.' );
     
          % Add datestamp and reference id UIControls
          str = sprintf ( 'Printed @ %s', datestr(now) );
          uicontrol ( 'parent',hFig, 'style','text', 'units','normalized', ...
                      'position',[0 0 1 0.07], 'string',str, 'BackgroundColor','white' );
        end
      end
    end

    When we run the above we can see that the disp message is displayed twice, because the property has two get calls in the print function. We can easily solve this by saving a temp variable that is created the first time it is run.

    The next thing we need to do is to clean up afterwards, i.e. remove the uicontrols and reset the temp variable to ensure that any future print events are captured.
    Here you might think the second get call I mentioned above was post printing, but it’s not. So we need to capture another event to do the cleaning up.

    In this instance I thought about what was likely to happen – some sort of user interaction, e.g. a mouse move, press or key press. So we can listen for any of those events and run our clean up method. This is shown in the full code below:

    % PrintListenerDemo - Demo of print listener methodology
    classdef PrintListenerDemo
      properties
        referenceNo = 'R1234-56'
      end
     
      methods (Access=public)
        function obj = PrintListenerDemo
          hFig = figure;
          [x,y,z] = peaks(75);
          surf ( x, y, z );
     
          % add listener on event to prepare the figure for printing
          addlistener ( hFig, 'PaperPositionMode', 'PreGet', @obj.Prep );      
     
          % add a few different ways to clean up
          addlistener ( hFig, 'ButtonDown', @obj.CleanUp );
          addlistener ( hFig, 'WindowKeyPress', @obj.CleanUp );
          addlistener ( hFig, 'WindowMouseMotion', @obj.CleanUp );
     
          % Testing only:
          evalin ( 'base', 'print ( gcf, ''-dmeta'' )' );  % simulate user action in command-line
          print(hFig,'-dmeta');    % simulate programmatic printout
        end
     
        function Prep(obj, hFig, varargin)
          try
            hFig.ApplicationData.printPrepDone;
            return % If variable set do not run this method again
          end
          disp ( 'preparing for print.' );
     
          % create the date string
          str1 = sprintf ( 'Printed @ %s', datestr(now) );
          str2 = sprintf ( 'Reference: %s', obj.referenceNo );
     
          % create 2 UI controls to contain the information requested in the image
          hFig.ApplicationData.UIC1 = uicontrol ( 'parent',hFig, 'style','text', 'units','norm', 'string',str1, 'BackgroundColor','w', 'position',[0 0 1 0.07] );
          hFig.ApplicationData.UIC2 = uicontrol ( 'parent',hFig, 'style','text', 'units','norm', 'string',str2, 'BackgroundColor','w', 'position',[0 0.93 1 0.07] );
     
          % Save a temp variable to stop this function being called many times.
          hFig.ApplicationData.printPrepDone = true;
        end
     
        function CleanUp(obj, hFig, varargin)
          try
            if hFig.ApplicationData.printPrepDone
              % Clean up the uicontrols
              disp ( 'clean up post printing event' );
              delete ( hFig.ApplicationData.UIC1 );
              delete ( hFig.ApplicationData.UIC2 );
     
              % remove the temp variable, so the next print job will be captured
              hFig.ApplicationData = rmfield ( hFig.ApplicationData, 'printPrepDone' );
            end
          end
        end
      end
    end

    It is noted here that the datestamp and the reference number remain visible until the user interacts with the GUI but that’s a small price to pay.

    Any suggestions on other ways to clean up the print event afterwards? If so, please post a comment below. Alternatively if you have used events and listeners in an unusual way please share this as well.

    Conclusions

    1. It is possible to capture printout events in your code even when the print command is invoked programmatically, without a direct reference to your code
    2. We can use events for things that we might never have initially considered
    ]]>
    https://undocumentedmatlab.com/blog_old/capturing-print-events/feed 3
    Another couple of Matlab bugs and workaroundshttps://undocumentedmatlab.com/blog_old/couple-of-matlab-bugs-and-workarounds https://undocumentedmatlab.com/blog_old/couple-of-matlab-bugs-and-workarounds#comments Wed, 26 Nov 2014 18:00:27 +0000 https://undocumentedmatlab.com/?p=5272 Related posts:
    1. A couple of internal Matlab bugs and workarounds A couple of undocumented Matlab bugs have simple workarounds. ...
    2. FIG files format FIG files are actually MAT files in disguise. This article explains how this can be useful in Matlab applications....
    3. HG2 update HG2 appears to be nearing release. It is now a stable mature system. ...
    4. Matlab compiler bug and workaround Both the Matlab compiler and the publish function have errors when parsing block-comments in Matlab m-code. ...
    ]]>
    Every now and then I come across some internal Matlab bugs. In many cases I find a workaround and move on, sometimes bothering to report the bugs to MathWorks support, but often not. In truth, it’s a bit frustrating to hear the standard response that the issue [or “unexpected behavior”, but never “bug” – apparently that’s a taboo word] “has been reported to the development team and they will consider fixing it in one of the future releases of MATLAB”.

    To date I’ve reported dozens of bugs and as far as I can tell, few if any of them have actually been fixed, years after I’ve reported them. None of them appear on Matlab’s official bug parade, which is only a small subset of the full list that MathWorks keeps hidden for some unknown reason (update: see the discussion in the comments thread below, especially the input by Steve Eddins). Never mind, I don’t take it personally, I simply find a workaround and move on. I’ve already posted about this before. Today I’ll discuss two additional bugs I’ve run across once-too-often, and my workarounds:

    Nothing really earth-shattering, but annoying nonetheless.

    Saving non-Latin Command Window text using diary

    The diary function is well-known for saving Matlab’s Command-Window (CW) text to a file. The function has existed for the past two decades at least, possibly even longer.

    Unfortunately, perhaps the developer never thought that Matlab would be used outside the Americas and Western Europe, otherwise I cannot understand why to this day diary saves the text in ASCII format rather than the UTF-16 variant used by the CW. This works ok for basic Latin characters, but anyone who outputs Chinese, Japanese, Korean, Hindi, Arabic, Hebrew or other alphabets to the CW, and tries to save it using diary, will find the file unreadable.

    Here is a sample illustrative script, that outputs the Arabic word salaam (peace, سلام) to the CW and then tries to save this using diary. If you try it, you will see it ok in the CW, but garbage text in the generated text file:

    >> fname='diary_bug.txt'; diary(fname); disp(char([1587,1604,1575,1605])); diary off; winopen(fname)
    سلام

    The problem is that since diary assumes ASCII characters, any characters having a numeric value above 255 get truncated and are stored as invalid 1-byte characters, char(26) in this case.

    Here’s my workaround:

    % Output Command Window text to a text file
    function saveCmdWinText(filename)
        cmdWinDoc = com.mathworks.mde.cmdwin.CmdWinDocument.getInstance;
        txt = char(cmdWinDoc.getText(0,cmdWinDoc.getLength));
        fid = fopen(filename,'W');
        fwrite(fid,txt,'uint16');  % store as 2-byte characters
        fclose(fid);
        %winopen(filename);  % in case you wish to verify...
    end

    This works well, saving the characters in their original 2-byte format, for those alphabets that use 2-bytes: non-basic Latins, Greek, Cyrillic, Armenian, Arabic, Hebrew, Coptic, Syriac and Tāna (I don’t think there are more than a handful of Matlab users who use Coptic, Syriac or Tāna but never mind). However, UTF-8 specifies that CJK characters need 3-4 bytes and this is apparently not supported in Matlab, whose basic char data type only has 2 bytes, so I assume that Chinese, Japanese and Korean will probably require a different solution (perhaps the internal implementation of char and the CW is different in the Chinese/Japanese versions of Matlab, I really don’t know. If this is indeed the case, then perhaps a variant of my workaround can also be used for CJK output).

    Correction #1: I have learned since posting (see Steve Eddins’ comment below) that Matlab actually uses UTF-16 rather than UTF-8, solving the CJK issue. I humbly stand corrected.

    Correction #2: The saveCmdWinText code above saves the CW text in UTF-16 format. This may be problematic in some text editors that are not UTF-savvy. For such editors (or if your editor get confused with the various BOM/endianness options), consider saving the data in UTF-8 format – again, assuming you’re not using an alphabet [such as CJK] outside the ASCII range (thanks Rob):

    function saveCmdWinText_UTF8(filename)
        cmdWinDoc = com.mathworks.mde.cmdwin.CmdWinDocument.getInstance;
        txt = char(cmdWinDoc.getText(0,cmdWinDoc.getLength));
        fid = fopen(filename,'W','n','utf-8');
        fwrite(fid,txt,'char');
        fclose(fid);
        %winopen(filename);  % in case you wish to verify...
    end

    Also, this workaround is problematic in the sense that it’s a one-time operation that stores the entire CW text that is visible at that point. This is more limited than diary‘s ability to start and stop output recording in mid-run, and to record output on-the-fly (rather than only at the end). Still, it does provide a solution in case you output non-ASCII 2-byte characters to the CW.

    Update: I plan to post a utility to the Matlab File Exchange in the near future that will mimic diary‘s ability to start/stop text recording, rather than simply dumping the entire CW contents to file. I’ll update here when this utility is ready for download.

    There are various other bugs related to entering non-Latin (and specifically RTL) characters in the CW and the Matlab Editor. Solving the diary bug is certainly the least of these worries. Life goes on…

    p.s. – I typically use this translator to convert from native script to UTF codes that can be used in Matlab. I’m sure there are plenty of other translators, but this one does the job well enough for me.

    For people interested in learning more about the Command Window internals, take a look at my cprintf and setPrompt utilities.

    cprintf usage examples

    cprintf usage examples

    setPrompt usage examples

    setPrompt usage examples

    Printing GUIs reliably

    Matlab has always tried to be far too sophisticated for its own good when printing figures. There’s plenty of internal code that tries to handle numerous circumstances in the figure contents for optimal output. Unfortunately, this code also has many bugs. Try printing even a slightly-complex GUI containing panels and/or Java controls and you’ll see components overlapping each other, not being printed, and/or being rendered incorrectly in the printed output. Not to mention the visible flicker that happens when Matlab modifies the figure in preparation for printing, and then modifies it back to the original.

    All this when a simple printout of a screen-capture would be both much faster and 100% reliable.

    Which is where my ScreenCapture utility comes in. Unlike Matlab’s print and getframe, ScreenCapture takes an actual screen-capture of an entire figure, or part of a figure (or even a desktop area outside any Matlab figure), and can then send the resulting image to a Matlab variable (2D RGB image), an image file, system clipboard, or the printer. We can easily modify the <Print> toolbar button and menu item to use this utility rather than the builtin print function:

    Matlab's default toolbar Print action

    Matlab's default toolbar Print action

    hToolbar = findall(gcf,'tag','FigureToolBar');
    hPrintButton = findall(hToolbar, 'tag','Standard.PrintFigure');
    set(hPrintButton, 'ClickedCallback','screencapture(gcbf,[],''printer'')');
     
    hPrintMenuItem = findall(gcf, 'type','uimenu', 'tag','printMenu');
    set(hPrintMenuItem,      'Callback','screencapture(gcbf,[],''printer'')');

    This prints the entire figure, including the frame, menubar and toolbar (if any). If you just wish to print the figure’s content area, then make sure to create a top-level uipanel that spans the entire content area and in which all the contents are included. Then simply pass this top-level container handle to ScreenCapture:

    hTopLevelContainer = uipanel('BorderType','none', 'Parent',gcf, 'Units','norm', 'Pos',[0,0,1,1]);
    ...
    hToolbar = findall(gcf,'tag','FigureToolBar');
    hPrintButton = findall(hToolbar, 'tag','Standard.PrintFigure');
    set(hPrintButton, 'ClickedCallback',@(h,e)screencapture(hTopLevelContainer,[],'printer'));
     
    hPrintMenuItem = findall(gcf, 'type','uimenu', 'tag','printMenu');
    set(hPrintMenuItem,      'Callback',@(h,e)screencapture(hTopLevelContainer,[],'printer'));

    In certain cases (depending on platform/OS/Matlab-release), the result may capture a few pixels from the figure’s window frame. This can easily be corrected by specifying a small offset to ScreenCapture:

    set(hPrintButton, 'ClickedCallback',@(h,e)printPanel(hTopLevelContainer));
    set(hPrintMenuItem,      'Callback',@(h,e)printPanel(hTopLevelContainer));
     
    function printPanel(hTopLevelContainer)
        pos = getpixelposition(hTopLevelContainer);
        screencapture(hTopLevelContainer, pos+[2,4,0,0], 'printer');
    end
    ]]>
    https://undocumentedmatlab.com/blog_old/couple-of-matlab-bugs-and-workarounds/feed 32
    Customizing figure toolbar backgroundhttps://undocumentedmatlab.com/blog_old/customizing-figure-toolbar-background https://undocumentedmatlab.com/blog_old/customizing-figure-toolbar-background#comments Wed, 20 Feb 2013 18:00:35 +0000 https://undocumentedmatlab.com/?p=3634 Related posts:
    1. Toolbar button labels GUI toolbar button labels can easily be set and customized using underlying Java components. ...
    2. Blurred Matlab figure window Matlab figure windows can be blurred using a semi-transparent overlaid window - this article explains how...
    3. Minimize/maximize figure window Matlab figure windows can easily be maximized, minimized and restored using a bit of undocumented magic powder...
    4. Builtin PopupPanel widget We can use a built-in Matlab popup-panel widget control to display lightweight popups that are attached to a figure window. ...
    ]]>
    In one of my projects, I needed to present a radar (polar) plot. Such plots are usually drawn on a black background and I wanted all the plot controls to blend into this background.

    Matlab figure having black toolbar background

    Matlab figure having black toolbar background

    For the plot itself I used a variation of Matlab’s buggy polar function, which I modified to enable proper dynamic resize / zoom / pan, bypass figure-renderer issues with patches and data-cursors, and other similar annoyances. Pretty standard stuff.

    For the slider I’ve used a javax.swing.JSlider having a continuous-movement callback. Again, for readers of this blog this is nothing special:

    [jSlider,hSlider] = javacomponent('javax.swing.JSlider',[0,0,.01,0.1],hFig);
    set(hSlider, 'Units','norm','pos',[.15,0,.7,.05]);
    set(jSlider, 'Background',java.awt.Color.black, ...
                 'Value',0, 'Maximum',duration, ...
                 'StateChangedCallback',{@cbSlider,hFig,axPlayback});

    Setting the background color for all the GUI components to black was easy. But setting the toolbar’s background to black turned out to be a bit more interesting, and is the topic of this week’s article.

    Standard Matlab figure toolbar - yuck!

    Standard Matlab figure toolbar - yuck!

    The first step, naturally, is to get the toolbar’s handle:

    hToolbar = findall(hFig,'tag','FigureToolBar');

    In my case, I programmatically create the figure and use the default figure toolbar, whose tag value is always ‘FigureToolBar’. If I had used a custom toolbar, I would naturally use the corresponding tag (for example, if you create a custom toolbar using GUIDE, then the tag name will probably be ‘toolbar1’ or something similar).

    Since I’m setting the figure programmatically, I need to manually remove several unuseful toolbar controls. I do this by directly accessing the toolbar control handles:

    delete(findall(hToolbar,'tag','Plottools.PlottoolsOn'))
    delete(findall(hToolbar,'tag','Plottools.PlottoolsOff'))
    delete(findall(hToolbar,'tag','Annotation.InsertColorbar'))
    delete(findall(hToolbar,'tag','DataManager.Linking'))
    delete(findall(hToolbar,'tag','Standard.EditPlot'))

    For setting the bgcolor, we get the toolbar’s underlying Java component, then sprinkle some Java magic power:

    % ensure the toolbar is visible onscreen
    drawnow;
     
    % Get the underlying JToolBar component
    jToolbar = get(get(hToolbar,'JavaContainer'),'ComponentPeer');
     
    % Set the bgcolor to black
    color = java.awt.Color.black;
    jToolbar.setBackground(color);
    jToolbar.getParent.getParent.setBackground(color);
     
    % Remove the toolbar border, to blend into figure contents
    jToolbar.setBorderPainted(false);
     
    % Remove the separator line between toolbar and contents
    jFrame = get(handle(hFig),'JavaFrame');
    jFrame.showTopSeparator(false);

    Unfortunately, this is not enough. The reason is that some of Matlab’s standard toolbar icons use non-opaque Java button controls (thereby showing the new black bgcolor), whereas other icons use opaque buttons, with a hard-coded gray background (I feel like spanking someone…). I’ve already touched upon this issue briefly a few years ago.

    Matlab figure toolbar with black background, some opaque buttons

    Matlab figure toolbar with black background, some opaque buttons

    Luckily, all is not lost: we simply need to loop over all the JToolBar’s components and force them to be non-opaque with a black bgcolor. In cases where the component is compound (e.g., the Brush Data uisplittool), we need to set the bgcolor for all the sub-components:

    jtbc = jToolbar.getComponents;
    for idx=1:length(jtbc)
        jtbc(idx).setOpaque(false);
        jtbc(idx).setBackground(color);
        for childIdx = 1 : length(jtbc(idx).getComponents)
            jtbc(idx).getComponent(childIdx-1).setBackground(color);
        end
    end

    …finally ending up with the blended appearance that appears at the top of this article.

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

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

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

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

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

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

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

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

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

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

    Modified standard figure menu-bar

    Modified standard figure menu-bar


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

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

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

    HTML-rendered menu items

    HTML-rendered menu items

    Customizing the standard toolbar’s “Open File” button

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

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

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

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

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

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

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

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

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

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

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

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

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

    Modified standard figure toolbar

    Modified standard figure toolbar

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

    That’s it. Quite painless in fact.

    ]]>
    https://undocumentedmatlab.com/blog_old/customizing-standard-figure-toolbar-menubar/feed 12
    Docking figures in compiled applicationshttps://undocumentedmatlab.com/blog_old/docking-figures-in-compiled-applications https://undocumentedmatlab.com/blog_old/docking-figures-in-compiled-applications#comments Wed, 15 Jun 2011 18:00:56 +0000 https://undocumentedmatlab.com/?p=2341 Related posts:
    1. Disabling menu entries in deployed docked figures Matlab's standard menu items can and should be removed from deployed docked figures. This article explains how. ...
    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. Frameless (undecorated) figure windows Matlab figure windows can be made undecorated (borderless, title-less). ...
    4. Figure window customizations Matlab figure windows can be customized in numerous manners using the underlying Java Frame reference. ...
    ]]>
    Up until Matlab release R2008a, the Matlab compiler enabled compiled Matlab applications to have dockable figure windows, which docked into a “Figures” container. Starting with R2008a, the compiler removed the figure’s docking capability and figures can no longer be docked.

    Well, at least not officially :-)

    The following trick restores the docking controls to figures in R2008a-compiled applications, enabling figure docking. Simply add one or both of the following alternatives in your application, after the figure has been created:

    % Alternative #1 - uses pure Matlab
    set(hFig, 'DockControls', 'on');
     
    % Alternative #2 - uses the underlying Java frame
    jFrame = get(handle(hFig), 'JavaFrame');
    try
       % This works up to R2011a
       jFrame.fFigureClient.setClientDockable(true);
    catch
       % This works from R2008b and up
       jFrame.fHG1Client.setClientDockable(true);
    end

    where hFig is the figure handle. This will have no effect for the regular interpreted (non-compiled) run of the application, where these controls are ‘on’ by default. But in the compiled application, although it may erroneously report that the controls are ‘on’, they are in fact ‘off’, so turning them ‘on’ fixes the problem.

    Matlab figure docking control

    Matlab figure docking control

    Note: the two variants in alternative #2 above are actually identical, it is simply that the relevant field name has changed: Up to R2008a, only the fFigureClient existed; in R2008b, the fHG1Client field was added, which was simply an alias for fFigureClient, holding the same reference handle, so either of these fields could be used (a corresponding fHG2Client was also added – more on HG1 and HG2 here). In R2011b (at least the pre-release), the fFigureClient alias field was dropped and only fHG1Client remained. While the field name has changed, the underlying docking functionality appears to have remained stable over all these releases. For the record, in answer to a user question below, these fields can be listed using the built in fieldnames function:

    % R2008b - R2011a:
    >> fieldnames(jFrame)
    ans = 
        'fFigureClient'
        'fHG2Client'
        'fHG1Client'
        'fUseHG2'
        'UICONTROLBACKGROUND_OS'
        'UICONTROLBACKGROUND_COMPATIBLE'

    I was reminded of this trick by Aurélien’s recent comment, where he mentions MathWorks so-called workaround for this problem, which (IMHO) is really not a work-around at all: MathWorks advises to modify our application to use – would you believe this – tabbed panels to “dock” the separate figures contents onto separate panels. Not to mention the fact that this so-called “solution” relies on undocumented and unsupported Matlab functionality (that of tabbed-panels) and requires major rework of existing applications, it also results in far inferior look-and-feel than simple docking as G-d intended…

    Since I have demonstrated above that the docking functionality actually exists in compiled apps just as in the interpreted m-file apps, I do not understand why MathWorks took such great pains to prevent this important functionality in the compiler. There must be some important reason for this, but I cannot think of any. Perhaps if there is enough public demand, MathWorks will agree to return the docking functionality.

    Unfortunately, I recently discovered that in the most recent compiler, that ships with R2011a, alternative #1 above (which uses pure Matlab) no longer works. Sometime between R2008a and R2011a MathWorks discovered my first back-door and closed it. Such a pity…

    Luckily, alternative #2 (which uses the underlying Java frame object) seems to still work, even on R2011a.

    I still haven’t tested this on R2011b’s compiler (whose pre-release has become available for download yesterday), but hopefully the trick above will continue to work on R2011b and on subsequent releases – please tell me if you find out otherwise.

    Addendum: Since 2013, possibly as a direct result of this post, MathWorks have prevented this workaround. MathWorks officially states that docking figures is not possible in deployed applications. I do not know the reason for this, and I have still not discovered if another workaround for this annoying limitation is possible.

    ]]>
    https://undocumentedmatlab.com/blog_old/docking-figures-in-compiled-applications/feed 30