Toolbar – 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 Improving graphics interactivityhttps://undocumentedmatlab.com/blog_old/improving-graphics-interactivity https://undocumentedmatlab.com/blog_old/improving-graphics-interactivity#comments Sun, 21 Apr 2019 21:03:10 +0000 https://undocumentedmatlab.com/?p=8723 Related posts:
  1. 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....
  2. Inactive Control Tooltips & Event Chaining Inactive Matlab uicontrols cannot normally display their tooltips. This article shows how to do this with a combination of undocumented Matlab and Java hacks....
  3. Performance: accessing handle properties Handle object property access (get/set) performance can be significantly improved using dot-notation. ...
  4. Transparent uipanels Matlab uipanels can be made transparent, for very useful effects. ...
]]>
Matlab release R2018b added the concept of axes-specific toolbars and default axes mouse interactivity. Accelerating MATLAB Performance Plain 2D plot axes have the following default interactions enabled by default: PanInteraction, ZoomInteraction, DataTipInteraction and RulerPanInteraction.

Unfortunately, I find that while the default interactions set is much more useful than the non-interactive default axes behavior in R2018a and earlier, it could still be improved in two important ways:

  1. Performance – Matlab’s builtin Interaction objects are very inefficient. In cases of multiple overlapping axes (which is very common in multi-tab GUIs or cases of various types of axes), instead of processing events for just the top visible axes, they process all the enabled interactions for *all* axes (including non-visible ones!). This is particularly problematic with the default DataTipInteraction – it includes a Linger object whose apparent purpose is to detect when the mouse lingers for enough time on top of a chart object, and displays a data-tip in such cases. Its internal code is both inefficient and processed multiple times (for each of the axes), as can be seen via a profiling session.
  2. Usability – In my experience, RegionZoomInteraction (which enables defining a region zoom-box via click-&-drag) is usually much more useful than PanInteraction for most plot types. ZoomInteraction, which is enabled by default only enables zooming-in and -out using the mouse-wheel, which is much less useful and more cumbersome to use than RegionZoomInteraction. The panning functionality can still be accessed interactively with the mouse by dragging the X and Y rulers (ticks) to each side.

For these reasons, I typically use the following function whenever I create new axes, to replace the default sluggish DataTipInteraction and PanInteraction with RegionZoomInteraction:

function axDefaultCreateFcn(hAxes, ~)
    try
        hAxes.Interactions = [zoomInteraction regionZoomInteraction rulerPanInteraction];
        hAxes.Toolbar = [];
    catch
        % ignore - old Matlab release
    end
end

The purpose of these two axes property changes shall become apparent below.

This function can either be called directly (axDefaultCreateFcn(hAxes), or as part of the containing figure’s creation script to ensure than any axes created in this figure has this fix applied:

set(hFig,'defaultAxesCreateFcn',@axDefaultCreateFcn);

Test setup

Figure with default axes toolbar and interactivity

Figure with default axes toolbar and interactivity

To test the changes, let’s prepare a figure with 10 tabs, with 10 overlapping panels and a single axes in each tab:

hFig = figure('Pos',[10,10,400,300]);
hTabGroup = uitabgroup(hFig);
for iTab = 1 : 10
    hTab = uitab(hTabGroup, 'title',num2str(iTab));
    hPanel = uipanel(hTab);
    for iPanel = 1 : 10
        hPanel = uipanel(hPanel);
    end
    hAxes(iTab) = axes(hPanel); %see MLint note below
    plot(hAxes(iTab),1:5,'-ob');
end
drawnow

p.s. – there’s a incorrect MLint (Code Analyzer) warning in line 9 about the call to axes(hPanel) being inefficient in a loop. Apparently, MLint incorrectly parses this function call as a request to make the axes in-focus, rather than as a request to create the axes in the specified hPanel parent container. We can safely ignore this warning.

Now let’s create a run-time test script that simulates 2000 mouse movements using java.awt.Robot:

tic
monitorPos = get(0,'MonitorPositions');
y0 = monitorPos(1,4) - 200;
robot = java.awt.Robot;
for iEvent = 1 : 2000
    robot.mouseMove(150, y0+mod(iEvent,100));
    drawnow
end
toc

This takes ~45 seconds to run on my laptop: ~23ms per mouse movement on average, with noticeable “linger” when the mouse pointer is near the plotted data line. Note that this figure is extremely simplistic – In a real-life program, the mouse events processing lag the mouse movements, making the GUI far more sluggish than the same GUI on R2018a or earlier. In fact, in one of my more complex GUIs, the entire GUI and Matlab itself came to a standstill that required killing the Matlab process, just by moving the mouse for several seconds.

Notice that at any time, only a single axes is actually visible in our test setup. The other 9 axes are not visible although their Visible property is 'on'. Despite this, when the mouse moves within the figure, these other axes unnecessarily process the mouse events.

Changing the default interactions

Let’s modify the axes creation script as I mentioned above, by changing the default interactions (note the highlighted code addition):

hFig = figure('Pos',[10,10,400,300]);
hTabGroup = uitabgroup(hFig);
for iTab = 1 : 10
    hTab = uitab(hTabGroup, 'title',num2str(iTab));
    hPanel = uipanel(hTab);
    for iPanel = 1 : 10
        hPanel = uipanel(hPanel);
    end
    hAxes(iTab) = axes(hPanel);
    plot(hAxes(iTab),1:5,'-ob');
    hAxes(iTab).Interactions = [zoomInteraction regionZoomInteraction rulerPanInteraction];end
drawnow

The test script now takes only 12 seconds to run – 4x faster than the default and yet IMHO with better interactivity (using RegionZoomInteraction).

Effects of the axes toolbar

The axes-specific toolbar, another innovation of R2018b, does not just have interactivity aspects, which are by themselves much-contested. A much less discussed aspect of the axes toolbar is that it degrades the overall performance of axes. The reason is that the axes toolbar’s transparency, visibility, background color and contents continuously update whenever the mouse moves within the axes area.

Since we have set up the default interactivity to a more-usable set above, and since we can replace the axes toolbar with figure-level toolbar controls, we can simply delete the axes-level toolbars for even more-improved performance:

hFig = figure('Pos',[10,10,400,300]);
hTabGroup = uitabgroup(hFig);
for iTab = 1 : 10
    hTab = uitab(hTabGroup, 'title',num2str(iTab));
    hPanel = uipanel(hTab);
    for iPanel = 1 : 10
        hPanel = uipanel(hPanel);
    end
    hAxes(iTab) = axes(hPanel);
    plot(hAxes(iTab),1:5,'-ob');
    hAxes(iTab).Interactions = [zoomInteraction regionZoomInteraction rulerPanInteraction];
    hAxes(iTab).Toolbar = [];end
drawnow

This brings the test script’s run-time down to 6 seconds – 7x faster than the default run-time. At ~3ms per mouse event, the GUI is now as performant and snippy as in R2018a, even with the new interactive mouse actions of R2018b active.

Conclusions

MathWorks definitely did not intend for this slow-down aspect, but it is an unfortunate by-product of the choice to auto-enable DataTipInteraction and of its sub-optimal implementation. Perhaps this side-effect was never noticed by MathWorks because the testing scripts probably had only a few axes in a very simple figure – in such a case the performance lags are very small and might have slipped under the radar. But I assume that many real-life complex GUIs will display significant lags in R2018b and newer Matlab releases, compared to R2018a and earlier releases. I assume that such users will be surprised/dismayed to discover that in R2018b their GUI not only interacts differently but also runs slower, although the program code has not changed.

One of the common claims that I often hear against using undocumented Matlab features is that the program might break in some future Matlab release that would not support some of these features. But users certainly do not expect that their programs might break in new Matlab releases when they only use documented features, as in this case. IMHO, this case (and others over the years) demonstrates that using undocumented features is usually not much riskier than using the standard documented features with regards to future compatibility, making the risk/reward ratio more favorable. In fact, of the ~400 posts that I have published in the past decade (this blog is already 10 years old, time flies…), very few tips no longer work in the latest Matlab release. When such forward compatibility issues do arise, whether with fully-documented or undocumented features, we can often find workarounds as I have shown above.

If your Matlab program could use a performance boost, I would be happy to assist making your program faster and more responsive. Don’t hesitate to reach out to me for a consulting quote.

]]>
https://undocumentedmatlab.com/blog_old/improving-graphics-interactivity/feed 7
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
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
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
ScreenCapture utilityhttps://undocumentedmatlab.com/blog_old/screencapture-utility https://undocumentedmatlab.com/blog_old/screencapture-utility#comments Wed, 15 Aug 2012 16:54:11 +0000 https://undocumentedmatlab.com/?p=3059 Related posts:
  1. GUI automation using a Robot This article explains how Java's Robot class can be used to programmatically control mouse and keyboard actions...
  2. GUI automation utilities This article explains a couple of Matlab utilities that use Java's Robot class to programmatically control mouse and keyboard actions...
  3. GUI integrated HTML panel Simple HTML can be presented in a Java component integrated in Matlab GUI, without requiring the heavy browser control....
  4. Using spinners in Matlab GUI Spinner controls can easily be added to Matlab GUI. This article explains how. ...
]]>
A few days ago, my ScreenCapture utility was selected as Matlab’s Pick of the Week (POTW). POTW selections are normally extremely useful, well-written and instructive utilities, which are both great to use in their own right, as well as a great source of knowledge about Matlab programming features and good practices. I follow the weekly POTW selections closely, and often learn new stuff from these utilities. I take pride in the fact that some of my utilities have been selected for inclusion in this unique set.

ScreenCapture enables Matlab users to take automated (programmatic) as well as interactive screen-captures of any Matlab GUI component or sub-region. This includes figure windows, axes, images, controls and even the Matlab Desktop. If the target handle for the capture is not specified, then ScreenCapture prompts the user to interactively select the capture region using an rbbox limiting box. ScreenCapture also includes a feature that plants a camera icon in the figure toolbar, such that clicking this icon will immediately trigger the interactive region-selection screen-capture.

Whichever manner the capture was made, the user then has the option of sending the output to Matlab (as a 3D RGB image matrix), or to one of the standard image file formats (e.g., JPG or PNG).

ScreenCapture has extensive help and is well-documented and relatively easy to use. For example:

figure; surf(peaks); imgData=screencapture(gcf); imshow(imgData);

ScreenCapture in action

ScreenCapture in action


Some additional usage examples:

imageData = screencapture;                     % interactively select screen-capture rectangle
imageData = screencapture(hListbox);           % capture image of a uicontrol
imageData = screencapture(0,  [20,30,40,50]);  % capture a small desktop sub-region
imageData = screencapture(gcf,[20,30,40,50]);  % capture a small figure sub-region
 
% capture a small sub-region of an axes
imageData = screencapture(gca,[10,20,30,40]);
imshow(imageData);  % display the captured image in a matlab figure
imwrite(imageData,'myImage.png');  % save the captured image to file
 
% capture a sub-region of an image
img = imread('cameraman.tif');
hImg = imshow(img);
screencapture(hImg,[60,35,140,80]);  % in data units, not pixel units
 
screencapture(gcf,[],'myFigure.jpg');                   % capture the entire figure into file
screencapture('handle',gcf,'filename','myFigure.jpg');  % same as previous
screencapture('toolbar',gcf);                           % adds a screen-capture button to gcf's toolbar
screencapture('toolbar',[],'file','sc.bmp');            % same, using a default output filename

Purely documented

Over the course of the past few years I have submitted 40 utilities to the Matlab File Exchange, several of which have been selected for POTW. Unfortunately, since most of my utilities employ undocumented Matlab features to some extent (I can’t help myself…), they are ineligible for being selected as POTF, useful and deserving as they may be. In fact, my cprintf utility, which was selected as POTW, was quickly deselected as POTW because of this very issue. MathWorks fears (and I can certainly understand the concern) that highlighting a utility that relies on some undocumented feature as POTW might be considered as an official endorsement of these features.

ScreenCapture is different in this regard: it uses purely documented Matlab functionality to achieve its aims, and apparently still succeeds in providing useful functionality. This does not mean that ScreenCapture uses pure Matlab. In fact, it relies on the Java Robot class‘s functionality of taking a screen-capture of a specified area of the screen. Using the Java Robot class in such a way is an entirely documented Matlab feature. I have discussed the Java Robot in two past articles on this blog, where guest blogger Kesh Ikuma explained (here and here) how it can be used to simulate mouse and keyboard actions programmatically.

Under the hood

ScreenCapture calculates the requested screen-capture rectangle coordinates and then invokes the Java Robot to take the actual bitmap screen-capture. The output is then converted into a Matlab image matrix for output, or stored in an image file, based on the user’s choice of parameters.

Some difficulties that I overcame when programming ScreenCapture:

  • The screen position of docked windows cannot be computed reliably. Docked windows therefore need to be automatically temporarily undocked for screen-capture.
  • Undocking in Windows 7 with Aero transparency features causes the Robot to take its screen-shot before the window becomes fully opaque. Adding a short delay in undocking solved this issue.
  • Images use reversed Y-axis (Y=0 is at the axes top, not bottom). Also, when specifying a sub-region for capture, many users are used to handling images using data units (e.g., for imcrop) rather than ScreenCapture’s standard pixel units. Taking screen-captures of images proved to be a non-trivial challenge indeed.
  • Different Matlab objects (controls, axes, figures) have different external borders and internal margins. I had to take these into account in order to achieve tight-fitting image captures of these objects.
  • Performance was a problem, and it turned out that the bottleneck was trying to convert from the Java image data format to Matlab’s image data format. A couple of suggestions by Jan Simon and Urs (us) Schwartz significantly improved this performance hotspot. I’ve submitted the relevant code snippets to MathWorks for incorporation in a published technical solution, and I was happy to see that they have indeed incorporated them into that solution.
  • Finally, I thought that adding a custom toolbar image would be a nice touch. Since I’m not much of an artist, creating the camera icon programmatically proved to be a bit of a challenge…

Please feel free to download ScreenCapture’s code and check how I chose to program around these issues.

TODO list

Some potentially-useful features have so far eluded me in ScreenCapture’s implementation. Perhaps one day I will find a way to do them:

  1. Enable output of the image data, as an image object, to the system clipboard. It is easy to serialize the data and store it as a string in the clipboard, using the built-in clipboard function. But we would not be able to paste this data as an image into an external editor or image-processing utility. I have not yet found an easy way to store the image data as an object, although it should not be very difficult to do (here’s a starter).
  2. When interactively selecting a screen-capture region, rbbox‘s starting point needs to be somewhere within the boundaries of a Matlab figure. The box can extend beyond the figure’s borders, but it has to start somewhere within the figure. I would like to be able to use rbbox without this limitation.

Addendum Jan 28. 2013: A new version of ScreenCapture was uploaded to the File Exchange today which appears to solve both of the TODO issues above: The copy-to-clipboard feature relies on Jiro Doke’s imclipboard utility as mentioned by Matt below — simply specify the ‘clipboard’ string as the capture target (rather than a filename); the solution of the rbbox-anywhere feature relies on using a temporary transparent window that spans the entire desktop area, capturing the user’s rbbox clicks anywhere within the desktop area. Interested readers can easily adapt the code to fit multiple monitors (I didn’t bother).

]]>
https://undocumentedmatlab.com/blog_old/screencapture-utility/feed 35
handle2struct, struct2handle & Matlab 8.0https://undocumentedmatlab.com/blog_old/handle2struct-struct2handle-and-matlab-8 https://undocumentedmatlab.com/blog_old/handle2struct-struct2handle-and-matlab-8#comments Wed, 29 Dec 2010 18:00:56 +0000 https://undocumentedmatlab.com/?p=2023 Related posts:
  1. getundoc – get undocumented object properties getundoc is a very simple utility that displays the hidden (undocumented) properties of a specified handle object....
  2. Customizing axes part 4 – additional properties Matlab HG2 axes can be customized in many different ways. This article explains some of the undocumented aspects. ...
  3. Plot line transparency and color gradient Static and interpolated (gradient) colors and transparency can be set for plot lines in HG2. ...
  4. Plot markers transparency and color gradient Matlab plot-line markers can be customized to have transparency and color gradients. ...
]]>
Last week I explained that FIG files are simply MAT files in disguise. Today, we look under the hood of Matlab’s hgsave function, which is used to save FIG files. We shall see that this is both useful and illuminating vis-a-vis Matlab’s future.

handle2struct

Under the hood, hgsave uses the semi-documented built-in handle2struct function to convert the figure handle into a Matlab struct that is then stored with a simple save (the same function that saves MAT files) function call.

The fact that handle2struct is semi-documented means that the function is explained in a help comment (which can be seen via the help command), that is nonetheless not part of the official doc sections. It is an unsupported feature originally intended only for internal Matlab use (which of course doesn’t mean we can’t use it).

handle2struct merits a dedicated mention, since I can envision several use-cases for storing only a specific GUI handle (for example, a uipanel, a specific graph, or a set of GUI controls’ state). In this case, all we need to do is to call handle2struct with the requested parent handle, then save the returned structure. So simple, so powerful. handle2struct automatically returns all the non-default property information, recursively in all the handle’s children.

Note that features that are not properties of displayed handles (camera position, 3D rotation/pan/zoom states, annotations, axes-linking etc.) are not processed by handle2struct. For storing the states of these features, you need to use some specific handling – see the code within %matlabroot%\toolbox\matlab\graphics\private\hgsaveStructDbl.m for details. Basically, hgsaveStructDbl.m reads the state of all these features and temporarily stores them in the base handle’s ApplicationData property; handle2struct then reads them as any other regular handle property data, and then hgsaveStructDbl.m clears the temporary data from the handle’s ApplicationData. We can use the same trick for any other application state, of course.

struct2handle

handle2struct has a reverse function – the semi-documented struct2handle. I use it for creating dynamic preference panels: As in Matlab’s Preferences window, I have a list of preference topics and a set of corresponding options panels. In my case, it was easy to design each panel as a separate FIG file using GUIDE. In run-time, I simply load the relevant panel from its FIG file as described above, and place it onscreen in a dedicated uipanel using struct2handle. This enables very easy maintenance of preference panels, without sacrificing any functionality.

Matlab's preferences panels

Matlab's preferences panels

Figure menus and toolbars are not normally stored by hgsave, unless you use the optional ‘all’ parameter (and correspondingly in hgload, if you choose to use it). handle2struct and handle2struct accept the same optional ‘all’ parameter as hgsave and hgload. Unfortunately, a warning message indicates that this option will be discontinued in some future Matlab version.

Which brings us to our final topic for today:

Matlab 8: Boldly going where no FIG has gone before…

Remember my post earlier this year about the new HG2 mechanism? I speculated that when MathWorks decides to release HG2, it will define this as a major Matlab release and label it Matlab 8.0.

The source code in hgsave.m appears to confirm my speculation. Here is the relevant code section (slightly edited for clarity), which speaks for itself:

% Decide which save code path to use
if ~feature('HGUsingMatlabClasses')   % <== existing HG
    % Warn if user passed in 'all' flag
    if SaveAll
        warning( 'MATLAB:hgsave:DeprecatedOption', ...
            'The ''all'' option to hgsave will be removed in a future release.');
    end
    hgS = hgsaveStructDbl(h, SaveAll);
    SaveVer = '070000';
    SaveOldFig = true;
 
else   % <== HG2
 
    % Warn if user passed in 'all' flag
    if SaveAll
        warning( 'MATLAB:hgsave:DeprecatedOption', ...
            'The ''all'' option to hgsave has been removed.');
    end
    if SaveOldFig
        hgS = hgsaveStructClass(h);
        SaveVer = '080000';
    else
        hgO = hgsaveObject(h);
        SaveVer = '080000';
    end
end
 
% Revision encoded as 2 digits for major revision,
% 2 digits for minor revision, and 2 digits for
% patch revision.  This is the minimum revision
% required to fully support the file format.
% e.g. 070000 means 7.0.0

As can be seen, when Matlab starts using HG2 (perhaps in 2011?), the top-level structure node will be called “hgS_080000”, indicating Matlab 8.0. QED.

As a side-note, note that in HG2/Matlab8, although the comment about using ‘all’ indicates that it has been removed, in practice it is still accepted (although not being used). This will enable your code to be backward-compatible whenever HG2 launches, and future-compatible today.

Have you used handle2struct or struct2handle? If so, please share your experience in a comment.

Let the upcoming 2011 be a year filled with revelations, announcements and fulfillment! Happy New Year everybody!

]]>
https://undocumentedmatlab.com/blog_old/handle2struct-struct2handle-and-matlab-8/feed 11
uisplittool & uitogglesplittool callbackshttps://undocumentedmatlab.com/blog_old/uisplittool-uitogglesplittool-callbacks https://undocumentedmatlab.com/blog_old/uisplittool-uitogglesplittool-callbacks#comments Wed, 15 Dec 2010 18:00:35 +0000 https://undocumentedmatlab.com/?p=1999 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. 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. Inactive Control Tooltips & Event Chaining Inactive Matlab uicontrols cannot normally display their tooltips. This article shows how to do this with a combination of undocumented Matlab and Java hacks....
  4. uisplittool & uitogglesplittool Matlab's undocumented uisplittool and uitogglesplittool are powerful controls that can easily be added to Matlab toolbars - this article explains how...
]]>
Last week, I presented the undocumented uisplittool and uitogglesplittool functions and showed how they can be added to a Matlab figure toolbar. Today I wish to conclude this topic by explaining how these controls can be customized with user-defined callbacks and pop-up menus.

Callback functionality

Both uisplittool and uitogglesplittool have a Callback property, in addition to the standard ClickedCallback property that is available in uipushtools and uitoggletools.

The standard ClickedCallback is invoked when the main button is clicked, while Callback is invoked when the narrow arrow button is clicked. uitogglesplittool, like uitoggletool, also has settable OnCallback and OffCallback callback properties.

The accepted convention is that ClickedCallback should invoke the default control action (in our case, an Undo/Redo of the topmost uiundo action stack), while Callback should display a drop-down of selectable actions.

While this can be done programmatically using the Callback property, this functionality is already pre-built into uisplittool and uitogglesplittool for our benefit. To access it, we need to get the control’s underlying Java component.

Accessing the underlying Java component is normally done using the findjobj utility, but in this case we have a shortcut: the control handle’s hidden JavaContainer property that holds the underlying com.mathworks.hg.peer.SplitButtonPeer (or .ToggleSplitButtonPeer) Java reference handle. This Java object’s MenuComponent property returns a reference to the control’s drop-down sub-component (which is a com.mathworks.mwswing.MJPopupMenu object):

>> jUndo = get(hUndo,'JavaContainer')
jUndo =
com.mathworks.hg.peer.SplitButtonPeer@f09ad5
 
>> jMenu = get(jUndo,'MenuComponent')  % or: =jUndo.getMenuComponent
jMenu =
com.mathworks.mwswing.MJPopupMenu[Dropdown Picker ButtonMenu,...]

Let’s add a few simple textual options:

jOption1 = jMenu.add('Option #1');
jOption1 = jMenu.add('Option #2');
set(jOption1, 'ActionPerformedCallback', 'disp(''option #1'')');
set(jOption2, 'ActionPerformedCallback', {@myCallbackFcn, extraData});

setting uisplittool & uitogglesplittool popup-menus

setting uisplittool & uitogglesplittool popup-menus

Popup-menus are described in more detail elsewhere (and in future articles). In the past I have already explained how icons and HTML markup can be added to menu items. Sub-menus can also be added.

A complete example

Let’s now use this information, together with last year’s set of articles about Matlab’s undocumented uiundo functionality, to generate a complete and more realistic example, of undo/redo toolbar buttons.

Undo and redo are actions that are particularly suited for uisplittool, since its main button enables us to easily undo/redo the latest action (like a simple toolbar button, by clicking the main uisplittool button) as well as select items from the actions drop-down (like a combo-box, by clicking the attached arrow button) – all this using a single component.

% Display our GUI
hEditbox = uicontrol('style','edit', 'position',[20,60,40,40]); 
set(hEditbox, 'Enable','off', 'string','0');
hSlider = uicontrol('style','slider','userdata',hEditbox);
set(hSlider,'Callback',@test_uiundo);  
 
% Display the figure toolbar that was hidden by the uicontrol function
set(gcf,'Toolbar','figure');
 
% Add the Undo/Redo buttons
hToolbar = findall(gcf,'tag','FigureToolBar');
hUndo = uisplittool('parent',hToolbar);
hRedo = uitogglesplittool('parent',hToolbar);
 
% Load the Redo icon
icon = fullfile(matlabroot,'/toolbox/matlab/icons/greenarrowicon.gif');
[cdata,map] = imread(icon);
 
% Convert white pixels into a transparent background
map(find(map(:,1)+map(:,2)+map(:,3)==3)) = NaN;
 
% Convert into 3D RGB-space
cdataRedo = ind2rgb(cdata,map);
cdataUndo = cdataRedo(:,[16:-1:1],:);
 
% Add the icon (and its mirror image = undo) to latest toolbar
set(hUndo, 'cdata',cdataUndo, 'tooltip','undo','Separator','on', ...
           'ClickedCallback','uiundo(gcbf,''execUndo'')');
set(hRedo, 'cdata',cdataRedo, 'tooltip','redo', ...
           'ClickedCallback','uiundo(gcbf,''execRedo'')');
 
% Re-arrange the Undo/Redo buttons  
jToolbar = get(get(hToolbar,'JavaContainer'),'ComponentPeer');
jButtons = jToolbar.getComponents;
for buttonIdx = length(jButtons)-3 : -1 : 7  % end-to-front
   jToolbar.setComponentZOrder(jButtons(buttonIdx), buttonIdx+1);
end
jToolbar.setComponentZOrder(jButtons(end-2), 5);    % Separator
jToolbar.setComponentZOrder(jButtons(end-1), 6);    % Undo
jToolbar.setComponentZOrder(jButtons(end), 7);      % Redo
jToolbar.revalidate;
 
% Retrieve redo/undo object
undoObj = getappdata(gcf,'uitools_FigureToolManager');
if isempty(undoObj)
   undoObj = uitools.FigureToolManager(gcf);
   setappdata(gcf,'uitools_FigureToolManager',undoObj);
end
 
% Populate Undo actions drop-down list
jUndo = get(hUndo,'JavaContainer');
jMenu = get(jUndo,'MenuComponent');
undoActions = get(undoObj.CommandManager.UndoStack,'Name');
jMenu.removeAll;
for actionIdx = length(undoActions) : -1 : 1    % end-to-front
    jActionItem = jMenu.add(undoActions(actionIdx));
    set(jActionItem, 'ActionPerformedCallback', @myUndoCallbackFcn);
end
jToolbar.revalidate;
 
% Drop-down callback function
function myUndoCallbackFcn(jActionItem,hEvent)
    % user processing needs to be placed here
end  % myUndoCallbackFcn

undo/redo buttons implemented using uisplittool

undo/redo buttons implemented using uisplittool

In a real-world application, the code-segment above that populated the drop-down list would be placed within the slider’s test_uiundo() callback function, and we would set a similar drop-down for the hRedu button. In addition, we would dynamically modify the button tooltips. As a final customization, we could modify the figure’s main menu. Menu customization will be discussed in a future separate set of articles.

Have you used uisplittool or uitogglesplittool in your GUI? If so, please tell us what use you have made of them, in a comment below.

]]>
https://undocumentedmatlab.com/blog_old/uisplittool-uitogglesplittool-callbacks/feed 3
uisplittool & uitogglesplittoolhttps://undocumentedmatlab.com/blog_old/uisplittool-uitogglesplittool https://undocumentedmatlab.com/blog_old/uisplittool-uitogglesplittool#comments Thu, 09 Dec 2010 00:06:33 +0000 https://undocumentedmatlab.com/?p=1994 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. uisplittool & uitogglesplittool callbacks Matlab's undocumented uisplittool and uitogglesplittool are powerful toolbar controls - this article explains how to customize their behavior...
  3. Customizing uiundo This article describes how Matlab's undocumented uiundo undo/redo manager can be customized...
  4. Customizing the standard figure toolbar, menubar The standard figure toolbar and menubar can easily be modified to include a list of recently-used files....
]]>
Matlab 7.6 (R2008a) and onward contain a reference to uisplittool and uitogglesplittool in the javacomponent.m and %matlabroot%/bin/registry/hg.xml files. These are reported as built-in functions by the which function, although they have no corresponding m-file as other similar built-in functions (note the double ‘t’, as in split-tool):

>> which uisplittool
built-in (C:\Matlab\R2010b\toolbox\matlab\uitools\uisplittool)

These uitools are entirely undocumented, even today (R2010b). They puzzled me for a very long time. An acute reader (Jeremy Raymonds) suggested they are related to toolbars, like other uitools such as the uipushtool and uitoggletool. This turned out to be the missing clue that unveiled these useful tools:

So what are uisplittool and uitogglesplittool?

Both uisplittool and uitogglesplittool are basic Handle-Graphics building blocks used in Matlab toolbars, similarly to the well-documented uipushtool and uitoggletool.

uisplittool presents a simple drop-down, whereas uitogglesplittool presents a drop-down that is also selectable.

The Publish and Run controls on the Matlab Editor’s toolbar are examples of uisplittool, and so are the Brush / Select-Data control on the figure toolbar, and the plot-selection drop-down on the Matlab Desktop’s Workspace toolbar:

uisplittool in action in the Matlab Desktop

uisplittool in action in the Matlab Desktop

Adding uisplittool and uitogglesplittool to a toolbar

Adding a uisplittool and uitogglesplittool to a toolbar is done in a similar manner to adding uipushtools and uitoggletools:

hToolbar = findall(gcf,'tag','FigureToolBar');
hUndo=uisplittool('parent',hToolbar);       % uisplittool
hRedo=uitogglesplittool('parent',hToolbar); % uitogglesplittool

Like uipushtool and uitoggletool, uisplittool and uitogglesplittool also have unique Type property values, ‘uisplittool’ and ‘uitogglesplittool’ respectively. The handles can also be tested using the built-in isa function:

>> isa(handle(hUndo),'uisplittool')   % or: 'uitogglesplittool'
ans =
     1
>> class(handle(hUndo))
ans =
uisplittool

Just as with uipushtools and uitoggletools, the new buttons have an empty button-face appearance, until we fix their CData, Tooltip and similar settable properties:

% Load the Redo icon
icon = fullfile(matlabroot,'/toolbox/matlab/icons/greenarrowicon.gif');
[cdata,map] = imread(icon);
 
% Convert white pixels into a transparent background
map(find(map(:,1)+map(:,2)+map(:,3)==3)) = NaN;
 
% Convert into 3D RGB-space
cdataRedo = ind2rgb(cdata,map);
cdataUndo = cdataRedo(:,[16:-1:1],:);
 
% Add the icon (and its mirror image = undo) to latest toolbar
set(hUndo, 'cdata',cdataUndo, 'tooltip','undo','Separator','on', ...
           'ClickedCallback','uiundo(gcbf,''execUndo'')');
set(hRedo, 'cdata',cdataRedo, 'tooltip','redo', ...
           'ClickedCallback','uiundo(gcbf,''execRedo'')');

User-created uisplittool & uitogglesplittool toolbar buttons

User-created uisplittool & uitogglesplittool toolbar buttons

Note that the controls can be created with these properties in a single command:

hUndo = uisplittool('parent',hToolbar, 'cdata',cdataRedo, ...);

Re-arranging the toolbar controls placement

Let us now re-arrange our toolbar buttons. Unfortunately, a bug causes uisplittools and uitogglesplittools to always be placed flush-left when the toolbar’s children are re-arranged (anyone at TMW reading this in time for the R2011a bug-parade selection?).

So, we can’t re-arrange the buttons at the HG-children level. Luckily, we can re-arrange directly at the Java level (note that until now, the entire discussion of uisplittool and uitogglesplittool was purely Matlab-based):

jToolbar = get(get(hToolbar,'JavaContainer'),'ComponentPeer');
jButtons = jToolbar.getComponents;
for buttonId = length(jButtons)-3 : -1 : 7  % end-to-front
   jToolbar.setComponentZOrder(jButtons(buttonId), buttonId+1);
end
jToolbar.setComponentZOrder(jButtons(end-2), 5);   % Separator
jToolbar.setComponentZOrder(jButtons(end-1), 6);   % Undo
jToolbar.setComponentZOrder(jButtons(end), 7);     % Redo
jToolbar.revalidate;

Re-arranged uisplittool & uitogglesplittool toolbar buttons

Re-arranged uisplittool & uitogglesplittool toolbar buttons
(not as simple as it may sound)

Next week, I will combine the information in this article, with last year’s articles about uiundo, and show how we can create a dynamic figure toolbar drop-down of undo/redo events. Here is a preview to whet your appetite:

undo/redo buttons implemented using uisplittool

undo/redo buttons implemented using uisplittool

]]>
https://undocumentedmatlab.com/blog_old/uisplittool-uitogglesplittool/feed 9
Modifying default toolbar/menubar actionshttps://undocumentedmatlab.com/blog_old/modifying-default-toolbar-menubar-actions https://undocumentedmatlab.com/blog_old/modifying-default-toolbar-menubar-actions#comments Wed, 02 Jun 2010 14:08:19 +0000 https://undocumentedmatlab.com/?p=1430 Related posts:
  1. Accessing plot brushed data Plot data brushing can be accessed programmatically using very simple pure-Matlab code...
  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. Graphic sizing in Matlab R2015b Matlab release R2015b's new "DPI-aware" nature broke some important functionality. Here's what can be done... ...
]]>
Did you ever wish to modify Matlab’s default toolbar/menubar items?

I recently consulted to a client who needed to modify the default behavior of the legend action in the toolbar, and the corresponding item on the main menu (Insert / Legend). The official version is that only user-added items can be customized, whereas standard Matlab items cannot.

Luckily, this can indeed be done using simple pure-Matlab code. The trick is to get the handles of the toolbar/menubar objects and then to modify their callback properties.

Default legend insertion action

Default legend insertion action

Using the toolbar/menubar item handles

Getting the handles can be done in several different ways. In my experience, using the object’s tag string is often easiest, fastest and more maintainable. Note that the Matlab toolbar and main menu handles are normally hidden (HandleVisibility = ‘off’). Therefore, in order to access them we need to use the findall function rather than the better-known findobj function. Also note that to set the callbacks we need to access differently-named properties: ClickedCallback for toolbar buttons, and Callback for menu items:

hToolLegend = findall(gcf,'tag','Annotation.InsertLegend');
set(hToolLegend, 'ClickedCallback',{@cbLegend,hFig,myData});
 
hMenuLegend = findall(gcf,'tag','figMenuInsertLegend');
set(hMenuLegend, 'Callback',{@cbLegend,hFig,myData});

As a side note, two undocumented/unsupported functions, uitool(hFig,tagName) and uigettoolbar, also retrieve toolbar items. Since using findall is so simple and more supported, I suggest using the findall approach.

To see the list of available toolbar/menubar tags, use the following code snippet:

% Toolbar tag names:
>> hToolbar = findall(gcf,'tag','FigureToolBar');
>> get(findall(hToolbar),'tag')
ans = 
    'FigureToolBar'
    'Plottools.PlottoolsOn'
    'Plottools.PlottoolsOff'
    'Annotation.InsertLegend'
    'Annotation.InsertColorbar'
    'DataManager.Linking'
    'Exploration.Brushing'
    'Exploration.DataCursor'
    'Exploration.Rotate'
    'Exploration.Pan'
    'Exploration.ZoomOut'
    'Exploration.ZoomIn'
    'Standard.EditPlot'
    'Standard.PrintFigure'
    'Standard.SaveFigure'
    'Standard.FileOpen'
    'Standard.NewFigure'
    ''
 
% Menu-bar tag names:
>> get(findall(gcf,'type','uimenu'),'tag')
ans = 
    'figMenuHelp'
    'figMenuWindow'
    'figMenuDesktop'
    'figMenuTools'
    'figMenuInsert'
    'figMenuView'
    'figMenuEdit'
    'figMenuFile'
    'figMenuHelpAbout'
    'figMenuHelpPatens'
    'figMenuHelpTerms'
    'figMenuHelpActivation'
    'figMenuDemos'
    'figMenuTutorials'
    'figMenuHelpUpdates'
    'figMenuGetTrials'
    'figMenuWeb'
    'figMenuHelpPrintingExport'
    'figMenuHelpAnnotatingGraphs'
    'figMenuHelpPlottingTools'
    'figMenuHelpGraphics'
    ''
    ''                    < = Note the missing tag names...
    ''
    'figMenuToolsBFDS'    <= note the duplicate tag names...
    'figMenuToolsBFDS'
    'figDataManagerBrushTools'
    'figMenuToolsAlign'
    'figMenuToolsAlign'
    ... (plus many many more...)

Unfortunately, as seen above, Matlab developers forgot to assign tags to some default toolbar/menubar items. Luckily, in my particular case, both legend handles (toolbar, menu) have valid tag names that can be used: ‘Annotation.InsertLegend’ and ‘figMenuInsertLegend’.

If an item’s tag is missing, you can always find its handle using its Parent, Label, Tooltip or Callback properties. For example:

hPrintMenuItem = get(findall(gcf,'Label','&Print...'));

Note that property values, such as the tag names or labels, are unsupported and undocumented. They may change without warning or notice between Matlab releases, and have indeed done so in the past. Therefore, if your code needs to be compatible with older Matlab releases, ensure that you cover all the possible property values, or use a different way to access the handles. While using the tag name or label as shown above is considered “Low risk” (I don’t expect it to break in the near future), their actual values should be considered somewhat more risky and we should therefore code defensively.

Another simple example: Print Preview

As another simple and very useful example, let’s modify the default Print action (and tooltip) on the figure toolbar to display the Print-Preview window rather than send the figure directly to the printer:

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','printpreview(gcbf)', 'TooltipString','Print Preview');

Matlab's Print Preview window

Matlab's Print Preview window

More advanced customization of the toolbar and menu items are possible, but require a bit of Java code. Examples of toolbar customizations were presented in past articles (here and here). A future article will explain how to customize menu items.

Have you found a nifty way to customize the menubar or toolbar? If so, please share it in the comments section below.

]]>
https://undocumentedmatlab.com/blog_old/modifying-default-toolbar-menubar-actions/feed 9
uiundo – Matlab’s undocumented undo/redo managerhttps://undocumentedmatlab.com/blog_old/uiundo-matlab-undocumented-undo-redo-manager https://undocumentedmatlab.com/blog_old/uiundo-matlab-undocumented-undo-redo-manager#comments Thu, 29 Oct 2009 22:11:11 +0000 https://undocumentedmatlab.com/?p=688 Related posts:
  1. Customizing uiundo This article describes how Matlab's undocumented uiundo undo/redo manager can be customized...
  2. uisplittool & uitogglesplittool Matlab's undocumented uisplittool and uitogglesplittool are powerful controls that can easily be added to Matlab toolbars - this article explains how...
  3. Adding dynamic properties to graphic handles It is easy and very useful to attach dynamic properties to Matlab graphics objects in run-time. ...
  4. New information on HG2 More information on Matlab's new HG2 object-oriented handle-graphics system...
]]>
Whenever we have a Matlab GUI containing user-modifiable controls (edit boxes, sliders, toggle buttons etc.), we may wish to include an undo/redo feature. This would normally be a painful programming task. Luckily, there is an undocumented built-in Matlab support for this functionality via the uiundo function. Note that uiundo and its functionality is not Java-based but rather uses Matlab’s classes and the similarly-undocumented schema-based object-oriented approach.

A couple of months ago, I explained how to customize the figure toolbar. In that article, I used the undocumented uiundo function as a target for the toolbar customization and promised to explain its functionality later. I would now like to explain uiundo and its usage.

The uiundo function is basically an accessor for Matlab’s built-in undo/redo manager object. It is located in the uitools folder (%MATLABROOT%\toolbox\matlab\uitools) and its @uiundo sub-folder. To use uiundo, simply define within each uicontrol’s callback function (where we normally place our application GUI logic) the name of the undo/redo action, what should be done to undo the action, and what should be done if the user wished to redo the action after undoing it. uiundo then takes care of adding this data to the figure’s undo/redo options under Edit in the main figure menu.

For example, let’s build a simple GUI consisting of a slider that controls the value of an edit box:

hEditbox = uicontrol('style','edit', 'position',[20,60,40,40]); 
set(hEditbox, 'Enable','off', 'string','0');
hSlider = uicontrol('style','slider','userdata',hEditbox);
callbackStr = 'set(get(gcbo,''userdata''),''string'',num2str(get(gcbo,''value'')))';
set(hSlider,'Callback',callbackStr);

Simple GUI with slider update of a numeric value

Simple GUI with slider update of a numeric value

Now, let’s attach undo/redo actions to the slider’s callback. First, place the following in test_uiundo.m:

% Main callback function for slider updates
function test_uiundo(varargin)
 
  % Update the edit box with the new value
  hEditbox = get(gcbo,'userdata');
  newVal = get(gcbo,'value');
  set(hEditbox,'string',num2str(newVal));
 
  % Retrieve and update the stored previous value
  oldVal = getappdata(gcbo,'oldValue');
  if isempty(oldVal),  oldVal=0;  end
  setappdata(gcbo,'oldValue',newVal);
 
  % Prepare an undo/redo action
  cmd.Name = sprintf('slider update (%g to %g)',oldVal,newVal);
 
  % Note: the following is not enough since it only
  %       updates the slider and not the editbox...
  %cmd.Function        = @set;                  % Redo action
  %cmd.Varargin        = {gcbo,'value',newVal};
  %cmd.InverseFunction = @set;                  % Undo action
  %cmd.InverseVarargin = {gcbo,'value',oldVal};
 
  % This takes care of the update problem...
  cmd.Function        = @internal_update;       % Redo action
  cmd.Varargin        = {gcbo,newVal,hEditbox};
  cmd.InverseFunction = @internal_update;       % Undo action
  cmd.InverseVarargin = {gcbo,oldVal,hEditbox};
 
  % Register the undo/redo action with the figure
  uiundo(gcbf,'function',cmd);
end
 
% Internal update function to update slider & editbox
function internal_update(hSlider,newValue,hEditbox)
  set(hSlider,'value',newValue);
  set(hEditbox,'string',num2str(newValue));
end

And now let’s point the slider’s callback to our new function:

>> set(hSlider,'Callback',@test_uiundo);

Undo/redo functionality integrated in the figure

Undo/redo functionality integrated in the figure

We can also invoke the current Undo and Redo actions programmatically, by calling uiundo with the ‘execUndo’ and ‘execRedo’ arguments:

uiundo(hFig,'execUndo');
uiundo(hFig,'execRedo');

When invoking the current Undo and Redo actions programmatically, we can ensure that this action would be invoked only if it is a specific action that is intended:

uiundo(hFig,'execUndo','Save data');  % should equal cmd.Name

We can use this approach to attach programmatic undo/redo actions to new toolbar or GUI buttons. The code for this was given in the above-mentioned article. Here is the end-result:


Undo/redo functionality integrated in the figure toolbar

Undo/redo functionality integrated in the figure toolbar

Undo/redo functionality integrated in the figure toolbar


In my next post, due next week, I will explore advanced customizations of this functionality.

]]>
https://undocumentedmatlab.com/blog_old/uiundo-matlab-undocumented-undo-redo-manager/feed 2
uicontrol side-effect: removing figure toolbarhttps://undocumentedmatlab.com/blog_old/uicontrol-side-effect-removing-figure-toolbar https://undocumentedmatlab.com/blog_old/uicontrol-side-effect-removing-figure-toolbar#respond Wed, 07 Oct 2009 21:41:31 +0000 https://undocumentedmatlab.com/?p=610 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. Panel-level uicontrols Matlab's uipanel contains a hidden handle to the title label, which can be modified into a checkbox or radio-button control...
  3. Multi-line uitable column headers Matlab uitables can present long column headers in multiple lines, for improved readability. ...
  4. HG2 update HG2 appears to be nearing release. It is now a stable mature system. ...
]]>
Earlier versions of Matlab had an undocumented side-effect in the uicontrol function, of removing the figure toolbar if the figure’s toolbar property was set to ‘auto’ (which is the default value for figures).

In order to restore the toolbar, or prevent its removal in the first place, set your figure’s toolbar property to ‘figure’. This should preferably be done immediately after creating the figure, or in its *_OpeningFcn() function if the figure was created using GUIDE:

set(hFig,'toolbar','figure');

The uicontrol issue is now documented in the latest Matlab 7.9 release (R2009b), although it was undocumented for many earlier Matlab releases. Nevertheless, the current documentation, coupled with the fact that this issue was widely reported in the CSSM newsgroup and so is not really innovative, made me hesitate before posting. But I’m currently on vacation and don’t have time for a more detailed article this week (I skipped last week entirely), so I apologize to anyone who feels disappointed. I promise to compensate when I get back from vacation…

A similar issue was reported for GUIDE-created figures, and was reportedly solved in Matlab 7.2 (R2006a).

]]>
https://undocumentedmatlab.com/blog_old/uicontrol-side-effect-removing-figure-toolbar/feed 0
Figure toolbar customizationshttps://undocumentedmatlab.com/blog_old/figure-toolbar-customizations https://undocumentedmatlab.com/blog_old/figure-toolbar-customizations#comments Wed, 02 Sep 2009 16:00:14 +0000 https://undocumentedmatlab.com/?p=564 Related posts:
  1. Detecting window focus events Matlab does not have any documented method to detect window focus events (gain/loss). This article describes an undocumented way to detect such events....
  2. Setting status-bar text The Matlab desktop and figure windows have a usable statusbar which can only be set using undocumented methods. This post shows how to set the status-bar text....
  3. Setting status-bar components Matlab status-bars are Java containers in which we can add GUI controls such as progress-bars, not just simple text labels...
  4. 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....
]]>
Last week, I described how to access existing Matlab figure toolbar icons and how to add non-button toolbar components. Today, I describe how the toolbar itself can be customized using undocumented functionality and properties.

All the important undocumented customizations can only be accessed via the toolbar’s Java handle, which is retrieved so:

hToolbar = findall(hFig,'tag','FigureToolBar');
jToolbar = get(get(hToolbar,'JavaContainer'),'ComponentPeer');

One interesting functionality is enabling a floating toolbar, via jToolbar.setFloatable(1). The toolbar can then be dragged from its docked position at the top of the figure menu, becoming enclosed in an independent floating window (a non-modal javax.swing.JDialog child of the parent figure, to be exact). Since this toolbar window has a very small initial size and no name, a simple immediate fix is required:

% Modify Java toolbar properties
jToolbar.setFloatable(1);
hjToolbar = handle(jToolbar,'CallbackProperties');
set(hjToolbar,'AncestorAddedCallback',@dockUndockCallbackFcn);
 
% Sample dockUndockCallbackFcn function
function dockUndockCallbackFcn(hjToolbar, eventdata)
   if hjToolbar.isFloating
      jToolbarWin = hjToolbar.getTopLevelAncestor;
      jToolbarWin.setTitle('Toolbar');
      %jToolbarWin.setResizable(1); %if you wish manual resize
      jToolbarWin.setPreferredSize(java.awt.Dimension(380,57));
      jToolbarWin.setSize(java.awt.Dimension(380,57));
      jToolbar.revalidate;  %repaint toolbar
      jToolbarWin.getParent.validate; %repaint parent figure
   end
end

Floating toolbar   ...and after minor fixes

Floating toolbar                 ...and after minor fixes        

Re-docking a floating toolbar can be done by simply closing the floating window – the toolbar then reappears in its default (top) position within the parent figure window.

There are other interesting functions/properties available via the Java interface – readers are encouraged to explore via the methods, methodsview, inspect functions, or my uiinspect utility.

For example, addGap() can be used to add a transparent gap between the rightmost toolbar component and the window border: this gap is kept even if the window is shrunk to a smaller width – the rightmost components disappear, maintaining the requested gap.

setBackground() sets the background color that is seen beneath transparent pixels of button images and gaps. Non-transparent (opaque or colored) pixels are not modified. If the button icons are improperly created, the result looks bad:

jToolbar.setBackground(java.awt.Color.cyan); %or: Color(0,1,1)

Default figure toolbar with cyan background

Default figure toolbar with cyan background

This problem can be fixed by looping over the toolbar icons and modifying the pixel values from their default gray background to transparent. An example for this practice was given at the beginning of last week’s article.

setMorePopupEnabled() is used to specify the behavior when the window resizes to such a small width that one or more toolbar buttons need to disappear – by default (=1 or true) the chevron (>>) mark appears on the toolbar’s right, enabling display of the missing buttons, but this behavior can be overridden (0 or false) to simply crop the extra buttons.

setRollover() controls the behavior when the mouse passes (“rolls”) over toolbar buttons. The default parameter (1 or true), displays a 3-dimensional button border, creating an embossing effect; this can be overridden (0 or false) to use a different 3D effect:

% Set non-default Rollover, MorePopupEnabled
jToolbar.setRollover(0);         % or: set(jToolbar,'Rollover','off');
jToolbar.setMorePopupEnabled(0); % or: set(jToolbar,'MorePopupEnabled','off');

default Rollover & MorePopupEnabled properties
non-default Rollover & MorePopupEnabled properties

default (top) and non-default (bottom)
Rollover & MorePopupEnabled properties

Remember that toolbars are simply containers for internal components, generally buttons and separators. These components may be accessed individually and manipulated. An example of such manipulation can be found in my FindJObj utility on the File Exchange, that lists the individual figure components: whenever the user selects a toolbar button (or any other Java component for that matter), its border is temporarily modified to a flashing red rectangle helping users understand the component’s location. Here’s the relevant code snip and screenshot (readers are encouraged to look at the actual code, which is more complex – FindJObj sub-function flashComponent()):

% Prepare the red border panel
oldBorder = jComponent.getBorder;
redBorder = javax.swing.border.LineBorder(java.awt.Color.red,2,0);
redBorderPanel = javax.swing.JPanel;
redBorderPanel.setBorder(redBorder);
redBorderPanel.setOpaque(0);  % transparent interior, red border
redBorderPanel.setBounds(jComponent.getBounds);
isSettable(compIdx) = ismethod(jComponent,'setBorder');
 
% flash by periodically displaying/hiding the panel
for idx = 1 : 2*numTimes
   if idx>1,  pause(delaySecs);  end  % don't pause at start
   visible = mod(idx,2);
   jParent = jComponent.getParent;
 
   % Most Java components allow modifying their borders
   if isSettable
      if visible
         % Set a red border
         jComp.setBorder(redBorder);
         try jComponent.setBorderPainted(1); catch, end
      else %if ~isempty(oldorder)
         % Remove red border by restoring the original border
         jComp.setBorder(oldBorder);
      end
      jComp.repaint;
 
   % Other Java components are highlighted by a transparent red-
   % border panel, placed on top of them in their parent's space
   elseif ~isempty(jParent)
      if visible
         % place the transparent red-border panel on top
         jParent.add(redBorderPanel);
         jParent.setComponentZOrder(redBorderPanel,0);
      else
         jParent.remove(redBorderPanel);
      end
      jParent.repaint;
   end
end  % idx flash loop

FindJObj - flashing red border around a toolbar icon

FindJObj - flashing red border around a toolbar icon

]]>
https://undocumentedmatlab.com/blog_old/figure-toolbar-customizations/feed 24
Figure toolbar componentshttps://undocumentedmatlab.com/blog_old/figure-toolbar-components https://undocumentedmatlab.com/blog_old/figure-toolbar-components#comments Thu, 27 Aug 2009 16:31:36 +0000 https://undocumentedmatlab.com/?p=541 Related posts:
  1. Uitab colors, icons and images Matlab's semi-documented tab panels can be customized using some undocumented hacks...
  2. Customizing uitree nodes – part 2 This article shows how Matlab GUI tree nodes can be customized with checkboxes and similar controls...
  3. Customizing uitree This article describes how to customize Matlab GUI tree controls created using the undocumented uitree function...
  4. Customizing uitree nodes – part 1 This article describes how to customize specific nodes of Matlab GUI tree controls created using the undocumented uitree function...
]]>
Toolbars are by now a staple of modern GUI design. An unobtrusive list of small icons enables easy access to multiple application actions without requiring large space for textual descriptions. Unfortunately, the built-in documented support for the Matlab toolbars is limited to adding icon buttons via the uipushtool and uitoggletool functions, and new toolbars containing them via the uitoolbar function. In this post I will introduce several additional customizations that rely on undocumented features.

This article will only describe figure toolbars. However, much of the discussion is also relevant to the desktop (Command Window) toolbars and interested users can adapt it accordingly.

Accessing toolbar buttons – undo/redo

Let’s start by adding undo/redo buttons to the existing figure toolbar. I am unclear why such an elementary feature was not included in the default figure toolbar, but this is a fact that can easily be remedied. In another post I describe uiundo, Matlab’s semi-documented support for undo/redo functionality, but for the present let’s assume we already have this functionality set up.

First, let’s prepare our icons, which are basically a green-filled triangle icon and its mirror image:

% Load the Redo icon
icon = fullfile(matlabroot,'/toolbox/matlab/icons/greenarrowicon.gif');
[cdata,map] = imread(icon);
 
% Convert white pixels into a transparent background
map(find(map(:,1)+map(:,2)+map(:,3)==3)) = NaN;
 
% Convert into 3D RGB-space
cdataRedo = ind2rgb(cdata,map);
cdataUndo = cdataRedo(:,[16:-1:1],:);

Now let’s add these icons to the default figure toolbar:

% Add the icon (and its mirror image = undo) to the latest toolbar
hUndo = uipushtool('cdata',cdataUndo, 'tooltip','undo', 'ClickedCallback','uiundo(gcbf,''execUndo'')');
hRedo = uipushtool('cdata',cdataRedo, 'tooltip','redo', 'ClickedCallback','uiundo(gcbf,''execRedo'')');

Undo/redo buttons

Undo/redo buttons

In the preceding screenshot, since no figure toolbar was previously shown, uipushtool added the undo and redo buttons to a new toolbar. Had the figure toolbar been visible, then the buttons would have been added to its right end. Since undo/redo buttons are normally requested near the left end of toolbars, we need to rearrange the toolbar buttons:

hToolbar = findall(hFig,'tag','FigureToolBar');
%hToolbar = get(hUndo,'Parent');  % an alternative
hButtons = findall(hToolbar);
set(hToolbar,'children',hButtons([4:end-4,2,3,end-3:end]));
set(hUndo,'Separator','on');

Undo/redo buttons in their expected positions

Undo/redo buttons in their expected positions

We would normally preserve hUndo and hRedo, and modify their Tooltip and Visible/Enable properties in run-time, based on the availability and name of the latest undo/redo actions:

% Retrieve redo/undo object
undoObj = getappdata(hFig,'uitools_FigureToolManager');
if isempty(undoObj)
   undoObj = uitools.FigureToolManager(hFig);
   setappdata(hFig,'uitools_FigureToolManager',undoObj);
end
 
% Customize the toolbar buttons
latestUndoAction = undoObj.CommandManager.peekundo;
if isempty(latestUndoAction)
   set(hUndo, 'Tooltip','', 'Enable','off');
else
   tooltipStr = ['undo' latestUndoAction.Name];
   set(hUndo, 'Tooltip',tooltipStr, 'Enable','on');
end

We can easily adapt the method I have just shown to modify/update existing toolbar icons: hiding/disabling them etc. based on the application needs at run-time.

Adding non-button toolbar components – undo dropdown

A more advanced customization is required if we wish to present the undo/redo actions in a drop-down (combo-box). Unfortunately, since Matlab only enables adding uipushtools and uitoggletools to toolbars, we need to use a Java component. The drawback of using such a component is that it is inaccessible via the toolbar’s Children property (implementation of the drop-down callback function is left as an exercise to the reader):

% Add undo dropdown list to the toolbar
jToolbar = get(get(hToolbar,'JavaContainer'),'ComponentPeer');
if ~isempty(jToolbar)
   undoActions = get(undoObj.CommandManager.UndoStack,'Name');
   jCombo = javax.swing.JComboBox(undoActions(end:-1:1));
   set(jCombo, 'ActionPerformedCallback', @myUndoCallbackFcn);
   jToolbar(1).add(jCombo,5); %5th position, after printer icon
   jToolbar(1).repaint;
   jToolbar(1).revalidate;
end
 
% Drop-down (combo-box) callback function
function myUndoCallbackFcn(hCombo,hEvent)
   itemIndex = get(hCombo,'SelectedIndex');  % 0=topmost item
   itemName  = get(hCombo,'SelectedItem');
   % user processing needs to be placed here
end

Undo dropdown list

Undo dropdown list

Note that the javax.swing.JComboBox constructor accepts a cell-array of strings (undoActions in the snippet above). A user-defined dropdownlist might be constructed as follows (also see a related CSSM thread):

...
dropdownStrings = {'here', 'there', 'everywhere'};
jCombo = javax.swing.JComboBox(dropdownStrings);
set(jCombo, 'ActionPerformedCallback', @myUndoCallbackFcn);
jToolbar(1).addSeparator;
jToolbar(1).add(jCombo);  % at end, following a separator mark
jToolbar(1).repaint;
jToolbar(1).revalidate;
...

A similar approach can be used to add checkboxes, radio-buttons and other non-button controls.

In next week’s post I will describe how the toolbar can be customized using undocumented functionality to achieve a non-default background, a floating toolbar (“palette”) effect and other interesting customizations. If you have any specific toolbar-related request, I’ll be happy to hear in the comments section below.

]]>
https://undocumentedmatlab.com/blog_old/figure-toolbar-components/feed 48