Undocumented Matlab
  • SERVICES
    • Consulting
    • Development
    • Training
    • Gallery
    • Testimonials
  • PRODUCTS
    • IQML: IQFeed-Matlab connector
    • IB-Matlab: InteractiveBrokers-Matlab connector
    • EODML: EODHistoricalData-Matlab connector
    • Webinars
  • BOOKS
    • Secrets of MATLAB-Java Programming
    • Accelerating MATLAB Performance
    • MATLAB Succinctly
  • ARTICLES
  • ABOUT
    • Policies
  • CONTACT
  • SERVICES
    • Consulting
    • Development
    • Training
    • Gallery
    • Testimonials
  • PRODUCTS
    • IQML: IQFeed-Matlab connector
    • IB-Matlab: InteractiveBrokers-Matlab connector
    • EODML: EODHistoricalData-Matlab connector
    • Webinars
  • BOOKS
    • Secrets of MATLAB-Java Programming
    • Accelerating MATLAB Performance
    • MATLAB Succinctly
  • ARTICLES
  • ABOUT
    • Policies
  • CONTACT

uiundo – Matlab's undocumented undo/redo manager

October 29, 2009 2 Comments

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);

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

% 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);

>> 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');

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

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.

Related posts:

  1. Customizing uiundo – This article describes how Matlab's undocumented uiundo undo/redo manager can be customized...
  2. uisplittool & uitogglesplittool callbacks – Matlab's undocumented uisplittool and uitogglesplittool are powerful toolbar controls - this article explains how to customize their behavior...
  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. Undocumented cursorbar object – Matlab's internal undocumented graphics.cursorbar object can be used to present dynamic data-tip cross-hairs...
  5. Types of undocumented Matlab aspects – This article lists the different types of undocumented/unsupported/hidden aspects in Matlab...
  6. Undocumented button highlighting – Matlab button uicontrols can easily be highlighted by simply setting their Value property. ...
Callbacks Pure Matlab schema.class Toolbar uitools uiundo Undocumented feature Undocumented function
Print Print
« Previous
Next »
2 Responses
  1. Xenia Oksana May 28, 2014 at 08:10 Reply

    Dear Mr. Altman,
    I try to write my own UNDO function for the matlab editbox. I use the Keypresscallback but that’s a little bit to late. I need the originaltext before the keypress and the CaretPosition, SelectionStart, SelectionEnd. Do you know how to get all values before the Keypresscallback?
    regards

    • Yair Altman June 3, 2014 at 08:20 Reply

      @Xenia – you could modify your KeyPressedCallback function to store the latest values of the edit string, CaretPosition etc. in a persistent manner. For example, you could use the persistent keyword or the component’s ApplicationData property (that you can access via Matlab’s builtin getappdata, setappdata functions. Then, in your callback function you can always check the new value and compare it to the persistent value that was stored in the last callback invocation.

Leave a Reply
HTML tags such as <b> or <i> are accepted.
Wrap code fragments inside <pre lang="matlab"> tags, like this:
<pre lang="matlab">
a = magic(3);
disp(sum(a))
</pre>
I reserve the right to edit/delete comments (read the site policies).
Not all comments will be answered. You can always email me (altmany at gmail) for private consulting.

Click here to cancel reply.

Useful links
  •  Email Yair Altman
  •  Subscribe to new posts (email)
  •  Subscribe to new posts (feed)
  •  Subscribe to new posts (reader)
  •  Subscribe to comments (feed)
 
Accelerating MATLAB Performance book
Recent Posts

Speeding-up builtin Matlab functions – part 3

Improving graphics interactivity

Interesting Matlab puzzle – analysis

Interesting Matlab puzzle

Undocumented plot marker types

Matlab toolstrip – part 9 (popup figures)

Matlab toolstrip – part 8 (galleries)

Matlab toolstrip – part 7 (selection controls)

Matlab toolstrip – part 6 (complex controls)

Matlab toolstrip – part 5 (icons)

Matlab toolstrip – part 4 (control customization)

Reverting axes controls in figure toolbar

Matlab toolstrip – part 3 (basic customization)

Matlab toolstrip – part 2 (ToolGroup App)

Matlab toolstrip – part 1

Categories
  • Desktop (45)
  • Figure window (59)
  • Guest bloggers (65)
  • GUI (165)
  • Handle graphics (84)
  • Hidden property (42)
  • Icons (15)
  • Java (174)
  • Listeners (22)
  • Memory (16)
  • Mex (13)
  • Presumed future risk (394)
    • High risk of breaking in future versions (100)
    • Low risk of breaking in future versions (160)
    • Medium risk of breaking in future versions (136)
  • Public presentation (6)
  • Semi-documented feature (10)
  • Semi-documented function (35)
  • Stock Matlab function (140)
  • Toolbox (10)
  • UI controls (52)
  • Uncategorized (13)
  • Undocumented feature (217)
  • Undocumented function (37)
Tags
ActiveX (6) AppDesigner (9) Callbacks (31) Compiler (10) Desktop (38) Donn Shull (10) Editor (8) Figure (19) FindJObj (27) GUI (141) GUIDE (8) Handle graphics (78) HG2 (34) Hidden property (51) HTML (26) Icons (9) Internal component (39) Java (178) JavaFrame (20) JIDE (19) JMI (8) Listener (17) Malcolm Lidierth (8) MCOS (11) Memory (13) Menubar (9) Mex (14) Optical illusion (11) Performance (78) Profiler (9) Pure Matlab (187) schema (7) schema.class (8) schema.prop (18) Semi-documented feature (6) Semi-documented function (33) Toolbar (14) Toolstrip (13) uicontrol (37) uifigure (8) UIInspect (12) uitools (20) Undocumented feature (187) Undocumented function (37) Undocumented property (20)
Recent Comments
  • Yair Altman (13 days 17 hours ago): @Veronica – you are using the new version of uitree, which uses HTML-based uifigures, and my post was about the Java-based uitree which uses legacy Matlab figures. For...
  • Veronica Taurino (13 days 17 hours ago): >> [txt1,txt2] ans = ‘abrakadabra’
  • Veronica Taurino (13 days 18 hours ago): Hello, I am just trying to change the uitree node name as you suggested: txt1 = 'abra'; txt2 = 'kadabra'; node.setName([txt1,txt2]); >> "Unrecognized method, property, or...
  • Yair Altman (16 days 17 hours ago): The version of JGraph that you downloaded uses a newer version of Java (11) than the one that Matlab supports (8). You need to either (1) find an earlier version of JGraph that...
  • mrv (16 days 22 hours ago): hello, I used MATLAB 2019b update9, I have add jgraphx.jar to javaclassapth, and restart matlab, but still got errors below: Warning: A Java exception occurred trying to load the...
  • xuejie wu (40 days 18 hours ago): Hi: I’m wondering if i can add my customized section or tab ?
  • Yair Altman (52 days 10 hours ago): @Sagar – use the view(az,el) function to rotate the 3D axes.
  • Sagar Chawla (52 days 10 hours ago): I want to know how to change the x-axis to the z-axis. I mean the position. Like if there is a 3d animated graph then how to change position of the axis. X-axis in place of...
  • Ren (52 days 10 hours ago): I noticed that xlsread will create a hidden and never-dying special server that always has priority when actxGetRunningServer is called. So this cause a problem that no matter how many...
  • Ben Abbott (56 days 1 hour ago): Thanks Yair, it was the second. I didn’t not include the drawnow ()
  • Yair Altman (56 days 4 hours ago): @Ben – it looks perfectly ok (with color gradient and all) on my R2022a… Perhaps you missed some of the steps (e.g. setting the ColorBinding to 'interpolated') or...
  • Ben Abbott (56 days 5 hours ago): The graded color is not working for me using R2021a. The plot “HG2 plot line color, transparency gradient” looks exactly like “Transparent HG2 plot...
  • Yair Altman (79 days 7 hours ago): Oliver – you probably forgot to update hMarkers.FaceColorType to ‘truecoloralpha‘: x=1:10; y=10*x; figure; hLine = plot(x,y,'o-'); drawnow...
  • Oliver (79 days 8 hours ago): This seems to have been disabled in the most recent version of Matlab (R2021b). When I use this method the hMarker.FaceColorData does change, but the markers are not made...
  • Yair Altman (98 days 5 hours ago): @Tim – the new uidatepicker() function only works with web-based figures (created using the uifigure() function or App Designer); it is not available on the legacy...
Contact us
Undocumented Matlab © 2009 - Yair Altman
This website and Octahedron Ltd. are not affiliated with The MathWorks Inc.; MATLAB® is a registered trademark of The MathWorks Inc.
Scroll to top