Uicontrol callbacks

In my previous post I showed how we can extensively customize a Matlab uicontrol’s appearance and behavior by accessing its undocumented underlying Java object. In this post I will show how to further customize the control’s behavior using the callbacks exposed by its underlying object.

Matlab’s uicontrol handles normally expose only a few event callbacks. These are ‘CreateFcn’, ‘DeleteFcn’, ‘ButtonDownFcn’, ‘KeyPressFcn’ and the control-specific ‘Callback’. In contrast, the underlying Java control exposes many more callbacks: 26 standard callbacks, plus a few control-specific callbacks, as follows:

  • AncestorMovedCallback – fired when one of the component’s container ancestors has changed its position relative to its container.
  • AncestorAddedCallback – fired when one of the component’s container ancestors has been added to another container
  • AncestorRemovedCallback – fired when one of the component’s container ancestors has been removed from the component’s hierarchy
  • AncestorResizedCallback – fired when one of the component’s container ancestor has been resized
  • ComponentAddedCallback – fired when a sub-component is added as a direct child to this component. Compare: ComponentRemovedCallback
  • ComponentHiddenCallback – fired when the component is hidden (setVisible(false)). Compare: ComponentShownCallback
  • ComponentMovedCallback – fired when the component is moved within its container. Since Java components are enclosed in a tight-fitting HG container, this callback will never fire for them: it does not fire when the container moves or resizes, only when the component’s starting position is moved within it.
  • ComponentRemovedCallback – fired when a sub-component is added as a direct child to this component. Compare: ComponentAddedCallback
  • ComponentResizedCallback – fired when the component is resized, either directly or because its container was resized.
  • ComponentShownCallback – fired when the component is displayed (setVisible(true)). Compare: ComponentHiddenCallback
  • FocusGainedCallback – fired when the component gains GUI focus, by mouse click, Tab click, or calling the component’s requestFocus() method.
  • FocusLostCallback – fired when the component loses focus to another component or window. Compare: FocusGainedCallback
  • HierarchyChangedCallback – fired when the component changes its ancestors (for example, moved from one panel to another).
  • KeyPressedCallback – fired continuously when any keyboard button (including Shift, Ctrl etc.) was pressed while the component had focus. The meta-data contains details about the specific key and modifiers (Alt, Shift, Ctrl, …) that were pressed. Compare: KeyReleasedCallback, KeyTypedCallback
  • KeyReleasedCallback – fired when a keyboard button was released while the component had focus. The meta-data contains details about the specific key and modifiers (Alt, Shift, Ctrl, …) that were pressed. Compare: KeyPressedCallback
  • KeyTypedCallback – similar to KeyPressedCallback, but only fired (continuously) when an actual printable character is clicked. Therefore, for Shift-A, KeyPressedCallback will fire twice (Shift, ‘A’) but KeyTypedCallback will only fire once. Compare: KeyPressedCallback, KeyReleasedCallback
  • MouseClickedCallback – fired when a mouse button is pressed and then released (=clicked) within the component’s bounds. If either the press or the release occurs outside the component’s bounds, the event will not fire. The figure’s ‘SelectionType’ property will be ‘normal’, ‘extend’ or ‘alt’ depending on which button was pressed. Compare: MousePressedCallback, MouseReleasedCallback.
  • MouseDraggedCallback – fired continuously when the mouse is clicked within the component’s bounds and then moved while the button is still depressed (i.e., dragged), even beyond the component’s bounds. The callback event’s meta-data will contain the delta-x and delta-y of the movement (positive for x-right/y-down; negative for x-left/y-up). Compare: MouseMovedCallback
  • MouseEnteredCallback – fired when the mouse is moved (depressed or not) into the component’s bounds. Compare: MouseExitedCallback
  • MouseExitedCallback – fired when the mouse is moved (depressed or not) out of the component’s bounds. Compare: MouseEnteredCallback
  • MouseMovedCallback – fired continuously when the mouse is moved undepressed within the component’s bounds. The callback event’s meta-data will contain the delta-x and delta-y of the movement (positive for x-right/y-down; negative for x-left/y-up). Compare: MouseDraggedCallback
  • MousePressedCallback – fired immediately when the mouse button is depressed (even before it was released) within the component’s bounds. The callback event’s meta-data will contain the click location within the component’s bounds. Compare: MouseClickedCallback, MouseReleasedCallback
  • MouseReleasedCallback – fired immediately when the mouse button is released within the component’s bounds. The callback event’s meta-data will contain the click location within the component’s bounds. Compare: MousePressedCallback
  • MouseWheelMovedCallback – fired immediately when the mouse wheel is turned (even before it was released) within the component’s bounds.
  • PropertyChangeCallback – fired when one of the component’s properties has changed. For example, after setting the component’s text, tooltip or border. Does not fire when modifying the component’s callback properties.
  • VetoableChangeCallback – fired upon a constrained property value change, allowing the callback to intercept and prevent the property change by raising an exception. Of all the Swing components, only JInternalFrame actually declares vetoable properties which can be intercepted.

It should be noted that these callbacks are standard in all Swing GUI controls. Thus, they can be used not just for Matlab uicontrols’ underlying Java objects, but also for any Swing component that you display using Matlab’s built-in javacomponent function.

The specific list of callbacks supported by each component depends on component type. As noted above, some components have additional specific callbacks. For example, ActionPerformedCallback is fired when a user has performed the main action associated with the control (selecting/clicking etc.). This is one of the most commonly used callbacks, one of the few exposed by Matlab HG handles (as the general-purpose ‘Callback’). This callback is implemented by JButton and JCheckBox (for instance), but not by JList or JMenu. CaretUpdateCallback and CaretPositionChangedCallback are only supported by text-entry controls like JTextField or JEditorPane, but not by JSlider or JTabbedPane. Other components have other such specific callbacks.

To see the full list of supported callbacks for a particular object, use the UIINSPECT utility from the File Exchange or use the following code snippet:

>> props = sort(fieldnames(get(javax.swing.JButton))); 
>> callbackNames = props(~cellfun(@isempty,regexp(props,'Callback$')));
callbackNames = 
    'ActionPerformedCallback'
    'AncestorAddedCallback'
    'AncestorMovedCallback'
    ...

A nice example of using Java callbacks to automatically select (highlight) the content text in a text-box when focus is gained was one of the first online posts in CSSM to use Matlab 7’s new javacomponent Swing integration.

Another typical usage is to set a continuously-firing callback whenever a slider uicontrol is dragged – the Matlab HG callback only fires once after the drag has completed, whereas we often wish to update some value or graphics during the drag events. This can easily be done using JSlider’s underlying object (a Swing JScrollBar) callbacks.


In order to prevent memory leaks in heavily-laden GUIs, it is advisable to get and set callback properties using the handle object, instead of directly on the “naked” Java reference. For this reason, using set/get is discouraged by MathWorks and may even be disabled in some future Matlab release:

jb = javax.swing.JButton;
jbh = handle(jb,'CallbackProperties');
% or for an existing uicontrol: jbh = findjobj(hButton);
set(jbh, 'ActionPerformedCallback',@myCallbackFcn)  % ok!
set(jb,  'ActionPerformedCallback',@myCallbackFcn)  % bad! memory leak

In some future post I plan to present more details about handle() and its intricacies. But in a nutshell, this code snippet is all you need to start working.

Callbacks can be set in the normal Matlab fashion, using one of three methods:

set(jbh, 'ActionPerformedCallback',@myCallbackFcn);
set(jbh, 'ActionPerformedCallback',{@myCallbackFcn,param1,param2});
set(jbh, 'ActionPerformedCallback','disp(123);');

I would be happy to hear how you use these newly-exposed callbacks in your application. Please leave your welcome comments below.

Categories: GUI, Java, Low risk of breaking in future versions, UI controls

Tags: , , , , ,

Bookmark and SharePrint Print

67 Responses to Uicontrol callbacks

  1. sleesh says:

    Hi Yair.

    I would just like to leave you a note, that I am always impressed by your comments, notes and posts on comp.soft-sys.matlab or TMW file-exchange.

    Seems as if you now decided to publish some deeper insights to the matter – great work!

    Since you asked for some input what people are interested in – my 2-cents:
    1. How to disable/enable single nodes of uitree?
    2. How to set the background color of the uitable, a single row, a single column (possible in 2008a and later, but impossible for me in 2007b)?

    • Thanks Sleesh.

      1. try setting the ‘enable’ property of the nodes

      2. in the old uitable, there are several ways to set the background color:
      a) Use each column’s cell renderer:

      cr = javax.swing.table.DefaultTableCellRenderer;
      cr.setForeground(java.awt.Color.red);
      cr.setBackground(java.awt.Color(0.2,0.3,0.8)); %dark-blue
      jtable.getColumnModel.getColumn(1).setCellRenderer(cr); % 0=first column; 1=second column; …

      b) use HTML data in the table: <html><font color=”red”>123.456 … – this is good for read-only cells but not good for editable cells because when you edit the cell you’ll see the HTML code…

      There is no easy way to set row colors – either set HTML colors programmatically or create a custom TableCellRenderer Java class

      Yair

  2. junziyang says:

    Is there anyway to wrap a JAVA component into a MATALB handle? I mean to retrun a matlab-like handle(a number) to the user after the creation of the Java component in MATLAB. While, only part of the properties of the JAVA object can be accessed through the handle.
    thanks.

    • Yair Altman says:

      @Junziyang – when creating a component you get a handle to the Java object that you can then use in Matlab using the built-in get/set functions etc. However, to prevent all sorts of issues (memory leaks, inaccessible callbacks etc.), you should normally use the returned object within a Matlab handle(), like so:

      javaObj = JavaClass(constructor_params);
      objHandle = handle(javaObj,’CallbackProperties’);
      % from now on, use get(objHandle,…) or set(objHandle,…) or objHandle.method()

      Yair

  3. Pingback: EditorMacro - assign a keyboard macro in the Matlab editor | Undocumented Matlab

  4. Pingback: Setting listbox mouse actions | Undocumented Matlab

  5. Pingback: Detecting window focus events | Undocumented Matlab

  6. Pingback: Continuous slider callback | Undocumented Matlab

  7. In answer to a CSSM question asking for an explanation of the memory leak problem when setting Matlab callbacks directly on the Java object (rather than on their handle), there is an official MathWorks post on this.

    Also see the following related CSSM threads here and here.

  8. Pingback: JIDE Property Grids | Undocumented Matlab

  9. iroln says:

    I want to use mouse uicontrol callbacks, but they don’t work. :(
    Here’s what I’m doing:

    function TestMouseCallbacks()
        hFig = figure();
        warning('off','MATLAB:HandleGraphics:ObsoletedProperty:JavaFrame');
        drawnow;
        jh = get(hFig, 'JavaFrame');
        jf = jh.fFigureClient.getWindow;
        jbh = handle(jf, 'CallbackProperties');
        set(jbh, 'MouseWheelMovedCallback', {@MousePressed})
    end
     
    function MousePressed(~, ~)
        disp('Pressed')
    end

    This code does not respond to mouse events (mouse events can be any).
    I also noticed that the keyboard events do not work and some other events.

    • Donn Shull says:

      @iroln Try placing your mouse over the title bar of your figure and then turning the mouse wheel.

      Donn

    • iroln says:

      @Donn Shull, I tried to do it. Mouse events are not working. “MousePressedCallback”, “MouseReleasedCallback”, “MouseMovedCallback” etc… None of them works.
      The problem is that I want use the MATLAB figure for high-performance display very big images, using HWND (Matlab graphics subsystem is very weak) . Сlasses to render images written in C++. I need to get this to work in Matlab. But I know bad java gui toolkits. Therefore have difficulty in understanding the bundles of Matlab-Java.

    • Donn Shull says:

      @iroln – When I tried your code it only recognized the the mouse and issued the callback when the mouse was over the window title area that is the area where it says Figure 1. The callbacks are not issued for any other area of the figure.

    • iroln says:

      @Donn Shull, I use Windows 7 x64 and MATLAB R2010b x64. What configuration do you use?

      At first I thought that to origin of events of the mouse hinders PanelContainer (Its events are working properly). For check I have written such code:

      jhp = get(jh, 'FigurePanelContainer');
      jhp.setSize(100, 100)

      But it didn’t help :)

      The following Callback works only within that PanelContainer:

      set(hFig, 'WindowButtonDownFcn', {@MousePressed})
    • Donn Shull says:

      @iroln – I am using windows 7 32 bit and the code you just sent works as you described

    • @iroln and Donn – apparently all mouse actions are delegated to the AxisCanvas component, so simply set your callback on that component. It works for me on R2010b. Here’s the complete code snippet:

      function TestMouseCallbacks()
        hFig = figure();
        warning('off','MATLAB:HandleGraphics:ObsoletedProperty:JavaFrame');
        drawnow;
        jh = get(hFig, 'JavaFrame');
        jf = jh.fFigureClient.getAxisComponent;  % note the change
        jbh = handle(jf, 'CallbackProperties');
        set(jbh, 'MouseWheelMovedCallback', @MousePressed)
      end
       
      function MousePressed(jObject, jEventData)
        disp('Pressed')
      end
    • iroln says:

      Thanks, Yair Altman!

  10. Sean Larkin says:

    I’m trying to use findjobj to get the java handle for a toolbar uitogglebutton. It does not find the handles for the button. When I call the function like this:
    findjobj;

    it finds the toolbar button. Why is this and is there a way I can modify findjobj to directly find toolbar buttons?

  11. Janos Marki says:

    Hi,

    I have a problem that I can’t seem to solve, and I can’t find the info.

    I execute a number of commands culminating in a plot. At this point, I need to intervene manually, which I thought of doing via the WindowKeyPressFcn callback of the figure I plotted in. Once done, I would like script execution to resume.

    However, whatever way I use to stop keyboard execution (keyboard, waitfor(figHand), no matter what I do, instead of the figure’s callback (scalSet.m) activating, the pressed key appears in the command window (i.e. I cannot make the figure the “active” object so the pressed key goes into it). It seems to me like this goes against the notion of having ready code, running the GUI, and then interacting with it (as interaction would already start whilst the script is run). Is this me trying to use Matlab in ways it has not been intended to work? Can it be done, or should I just do it differently?

    a111=figure('WindowKeyPressFcn',@scalSet); 
    waitfor(a111,'UserData','Done');

    …and the idea was to have one key (d) for the “Done” state in the callback function (waitfor would let the script carry on once this is triggered), which looks like this:

    function scalSet(src,eventdata)
    %function scalSet(src,eventdata)
    %
    %Function used to set scales with the mouse manually on plots with a colorbar
    %Press 'r' to narrow the scale by clicking two values on the
    %colorbar with the mouse
    %
    %Press 'w' to double the range
    %
    %enter set(gcf,'WindowKeyPressFcn',@scalSet) to add it to figures a
    %posteriori
     
    %we want to make the colorbar scaling smaller
    if strcmp(eventdata.Character,'r')
       scval=ginput(2);
       chs=get(src,'Children');
       for k=1:length(chs)
           nu=get(chs(k),'Type');
           if strcmp(nu,'axes')
             nu2=get(chs(k),'Tag');
               if ~strcmp(nu2,'Colorbar')
                   caxis(chs(k),[sort(scval(:,2))'])
               end
           end
       end   
    end
     
    %we want to widen it
    if strcmp(eventdata.Character,'w')
       scval=caxis;
       wid=scval(2)-scval(1);
       caxis([scval(1)-wid scval(2)+wid])
    end
     
    %we are done
    if strcmp(eventdata.Character,'d')
       set(src,'UserData','Done') 
    end

    Thanks!
    Janos

    • Janos Marki says:

      Update to previous: it now works. I think the problem was with the callback getting overwritten for some reason (only possible culprit: pcolor function). By inserting the callback handle again, it works without a hitch. Sorry for the hassle.

      Janos

      figure(a111)
      set(gcf,'WindowKeyPressFcn',@scalSet)
      waitfor(a111,'UserData','Done');
  12. Dave says:

    Yair, your knowledge is incredible, thank you for sharing.
    Please excuse my lack of understanding but it seems that whenever I try to use a callback it sends javahandle_withcallbacks.com.mathworks.mwswing.MJButton as the first parameter.

    function badprogrammingpractice
     
    hFig = figure('position', [300 300 600 400]);
    jbt = com.mathworks.mwswing.MJButton('click me');
    jbt.setBorder([])
    jbt.setBackground(java.awt.Color.white);
    jbt.setCursor(java.awt.Cursor.getPredefinedCursor(java.awt.Cursor.HAND_CURSOR));
    jbt.setFlyOverAppearance(1);
    bob = [1 2 3]
    jbtPosition = [0.1 0.1 0.3 0.3]
    [dummy,btContainer] = javacomponent(jbt,[0 0 1 1],hFig);
    set(btContainer, 'Units','Norm', 'Position',jbtPosition);
    hbt = handle(jbt,'CallbackProperties');
    set(hbt,'ActionPerformedCallback',@dosomething);
     
    function [mean,stdev] = dosomething(x,y)
    x

    output:

    bob =
    1 2 3
    jbtPosition =
    0.1000 0.1000 0.3000 0.3000
    x =
    javahandle_withcallbacks.com.mathworks.mwswing.MJButton
    >>

    • @Dave – this is correct. Matlab callbacks always send the originating object (in your case, a button which is actually an MJButton control) as the first parameter, and an eventData object as the second parameter. in eventData you can find information regarding the event, for example whether the button was clicked or right-clicked etc.

  13. Pingback: Matlab-Java memory leaks, performance | Undocumented Matlab

  14. Keith says:

    I’ve got a uicontrol popup menu (not shown below) and an edit uicontrol (shown here) the default text on the edit text box is ‘User Types Text Here’ I want this to disappear (set the string to []) whenever the user clicks on the edit text box, and reappear (set the string to the default text) if they deselect (by clicking something else) the textbox and the string is still []. Also I want the strings on two push buttons (accept and discard) to change appropriately (for example their string=’ ‘ if the string of the edit text box is the default string or empty and display ‘Accept text’ and ‘Discard text’, there’s also ‘Accept file’ and ‘Discard file’ strings depending whether a ‘fill with…’ popup menu is set to ‘fill with text’ or ‘fill with file’ and there are a few other options too) some code fragments are below

    the problem I was having was that PostSet listeners of the uicontrols ‘Selected’ property aren’t triggering and my attempt to use the java (via your findjobj function aren’t working either) maybe I’m doing it wrong
    changes to the string of the edit text box aren’t triggering PostSet listeners either (at least not until I click somewhere other than the editable text box, which is too late, I want the label of the accept discard buttons to appear before they click somewhere else)

    Can you help me?

    Thanks,

    Keith

    function make_user_text(hSynLowerLeftPanel,UserTextPos,WXWYInches,...
        usertextstate)
        SYNUD=getSynopsisUserData();
        GUIFont=SYNUD.Preferences.GUIFont;
        UserEditBackColor=SYNUD.UserEdit.Color.Back;
     
        WYButtonNorm=min(0.3/WXWYInches(2),UserTextPos(4)/3);
        UserTextPos(4)=UserTextPos(4)-WYButtonNorm;
        UTUD.DefaultString='User Types Text Here';
        hUserText=uicontrol('Parent',hSynLowerLeftPanel,'style','edit',...
            'units','normalized','position',UserTextPos,...
            'Tag','SynopsisUserText','Min',1,'Max',1000,...
            'FontName',GUIFont.Name,'FontSize',GUIFont.Size,...
            'BackgroundColor',UserEditBackColor);    
        jUserText=findjobj(hUserText)
        jUserText.FocusGainedCallback=@userTextSelectCallback;
        jUserText.FocusLostCallback=@userTextDeselectCallback;
     
        UTUD.hhUserText=handle(hUserText)
        UTUD.hUserTextString=findprop(UTUD.hhUserText,'String');
        UTUD.hListenUserTextString=handle.listener(UTUD.hhUserText,...
            UTUD.hUserTextString,'PropertyPostSet',...
            'listenerCallbackToSetAcceptDiscardLabels()');
        set(hUserText,'UserData',UTUD);
    ....
    end
     
    function userTextSelectCallback()
        %this needs to trigger whenever the user selects the user text box (an 
        %edit uicontrol)
        disp('userTextSelectCallback()');
        hUserText=findobj('Tag','SynopsisUserText');
        userTextString=get(hUserText,'String');
        UTUD=get(hUserText,'UserData');    
        if(strcmpi(userTextString,UTUD.DefaultString))
            %if/when you select the userText box and it has the default string
            %("User Types Text Here") then this removes the default string 
            %so the user doesn't have to backspace it away
            set(hUserText,'String',[]);
            userTextString=[];
        end
    end
     
    function userTextDeselectCallback()
        %this needs to trigger whenever the user deselects the user text box 
        %(an edit uicontrol)
        disp('userTextDeselectCallback()');
        hUserText=findobj('Tag','SynopsisUserText');
        userTextString=get(hUserText,'String');
        UTUD=get(hUserText,'UserData');
        if(isempty(userTextString))        
            %if/when you unselect (click anything else) user edit text box and
            %the user edit text box string is empty then this resets the string
            %to the default "User Types Text Here" String
            set(hUserText,'String',UTUD.DefaultString);
        end
    end
     
     
    function listenerCallbackToSetAcceptDiscardLabels()
        %this function assigns the appropriate labels to the 'Accept ...' and
        %'Discard ...' pushbuttons, where appropriate means:
        %' ' if the user text box isn't supposed to be receiving instructions
        %  OR
        %'... text' if the 'fill with ...' popupmenu is set to 'fill with text'
        %  OR
        %'... file' if the 'fill with ...' popupmenu is set to 'fill with file'
     
        hUserText=findobj('Tag','SynopsisUserText');
        userTextString=get(hUserText,'String');
        UTUD=get(hUserText,'UserData');
        hAcceptTextOrFilePush=findobj('Tag','SynopsisAcceptTextFilePush');
        hDiscardTextOrFilePush=findobj('Tag','SynopsisDiscardTextFilePush');
        if(isempty(userTextString)||strcmpi(userTextString,UTUD.DefaultString))
            set(hAcceptTextOrFilePush,'String',' ');
            set(hDiscardTextOrFilePush,'String',' ');
        else
            disp('listenerCallbackToSetAcceptDiscardLabels')
            hFillWithPopup=findobj('Tag','SynopsisFillWithPopup');
            FWUD=get(hFillWithPopup,'UserData');
            fwvalue=get(hFillWithPopup,'value')
            fwstring=get(hFillWithPopup,'string')
            fwstring=fwstring{fwvalue};
            if(strcmpi(fwstring,FWUD.String{2}))
                %fill with text so set the accept button to 'accept text',
                %and the discard button to 'discard text'
                ATFUD=get(hAcceptTextOrFilePush,'UserData');
                set(hAcceptTextOrFilePush,'String',ATFUD.String{1});
                DTFUD=get(hDiscardTextOrFilePush,'UserData');
                set(hDiscardTextOrFilePush,'String',DTFUD.String{1});                
            elseif(strcmpi(fwstring,FWUD.String{3}))
                %fill with file so set the accept button to 'accept file',
                %and the discard button to 'discard file'
                ATFUD=get(hAcceptTextOrFilePush,'UserData');
                set(hAcceptTextOrFilePush,'String',ATFUD.String{2});
                DTFUD=get(hDiscardTextOrFilePush,'UserData');
                set(hDiscardTextOrFilePush,'String',DTFUD.String{2});                                
            else
                %fill with ... or ' '
                set(hAcceptTextOrFilePush,'String',' ');
                set(hDiscardTextOrFilePush,'String',' ');
            end
        end
    end
  15. Oscar says:

    First of all, I would like to thank you for sharing your amazing knowledge.

    My problem is I’d like to execute a callback function when any key combination is pressed inside Matlab. I don’t know what object’s property I should modify. I basically want it to behave the same way it does when you press the combination CTRL+C but performing an specific action.

    Is there any way to do that?

    Thanks!

  16. Pingback: uiinspect | Undocumented Matlab

  17. Vladimir says:

    I have a memory leak kind of problem.
    I’m creating a jLabel object which is wrapped in the MATLAB class.
    I’m using the handle for all sets/gets to try prevent problems and memory leaks.

    I’m setting the MouseExitedCallback for jLabel using this code. It’s a method of the class:

        function SetMouseExitedCallback (obj, exitcallback)
            set (obj.hLabel, 'MouseExitedCallback', exitcallback)
        end

    This method is called from another class which actually contains the code for MouseExitedCallback.
    In that class it is called like this:

    obj.tooltip.SetMouseExitedCallback (@(src, event)obj.MouseExited);

    The problem that I’m getting is if I add this last line, if I try to edit files in the project it tells me that jLabel class is still in the memory.
    What can I do to prevent this?

    Vladimir

    • Malcolm Lidierth says:

      Try setting ‘MouseExitedCallback’ empty before destroying the object e.g. in a delete method.

    • Vladimir says:

      Yes, that was my thought also, but putting it in the delete (destructor) method didn’t work because destructor was never being called. Actually destructor was never called for another class also, the one where actual MouseExited() callback was defined.

      What worked at the end is to call:

      obj.tooltip.SetMouseExitedCallback ('');

      in the the method which is hiding the tooltip.

      Then after the application is closed VM calls destructors and destroy the object.

    • Malcolm Lidierth says:

      @Vladimir
      OK. Looks like the leaked reference means delete is not called.

      I encountered something like this with the Waterloo Swing Library objects. It seems circular references to objects can result in leaks so that a call to obj.delete() seems to work but referencing obj in the delete method throws an error because obj.isValid returns false. This was difficult to debug but trial-and-error provided a general solution that seems to work:

      The GTool superclass in Waterloo has some methods do deal with this, see here.
      Essentially the superclass provides an onCleanup method to be called from subclass constructors. That keeps a table of objects in the application data area of the MATLAB container being used. A delete callback on the MATLAB container removes all callback references to custom-objects in the table during deletion of the MATLAB container, and calls the custom-object’s delete method. GTool contains a static method, cleanupContainer to do that which targets only those callbacks I use.

      There has been some discussion about this on MATLAB Answers.

      My guess is this is the delete equivalent of referencing “this” during its construction in e.g. Java. For HG objects there is a BeingDeleted property.

  18. Sebastian K. says:

    Hey Yair,

    first of all: thank you very much for your effort presenting all – well probably ‘some of’ fits better here 😉 – your knowledge here in your blog as well as in your Book (I purchased it 2 weeks ago).

    Unfortunately, I got stuck with Callbacks of Figure Windows – since the whole GUI Container Hierarchy confuses me. What I want to do: fire a callback, when the title bar of a Figure Window is clicked e.g. to move the Figure Window. I can’t find the right place to put the callback function. Here’s a simple code snippet in which a callback is fired when the mouse is clicked anywhere in the contentPane… but that is not what I want. I would be pleased, if you could help me out. My Matlab Version: R2012b.

    function setWindowCallback( )
        % plot some data
        h = figure();
        plot(1:10);
        % get JavaFrame
        jf  = get(h, 'JavaFrame')
        % get JavaFrame by means of Yair's getjframe function
        jf2 = getjframe(h)
    	% get handle
        hf   = handle(jf.fHG1Client.getAxisComponent, 'CallbackProperties')
        %	get handle
        hf2  = handle(jf2, 'CallbackProperties')
        % set callback for action within ContentPane
        set(hf, 'MouseClickedCallback', @testAction)
        % set callback for entire Figure ( DOES NOT WORK :( )
        set(hf2, 'MouseClickedCallback', @testAction)
    end
     
    function testAction(jObject, jEvntData)
        display('Hello World')
    end
    • @Sebastian – thanks. Why not simply try placing a UDD listener on the figure’s Position property?

    • Malcolm Lidierth says:

      Yair’s answer is the simplest route. If you need Java you need, a component listener, not mouse because the mouse events are not in the content pane, as you say, and are absorbed by the title bar handlers. You can derive mouse position in the component listener (but working with mouse positions relative to a window being moved by the mouse can get tricky). For a component moved callback:

      >> temp = javaframe.getFigurePanelContainer();
      >> target = javax.swing.SwingUtilities.getRoot(temp);
      >> handle(target,'callbackproperties')
      ans =
      	javahandle_withcallbacks.com.mathworks.hg.peer.FigureFrameProxy$FigureFrame
       
      >> set(h, 'ComponentMovedCallback', 'disp(99)')
    • Sebastian K. says:

      @Yair: excellent solution! That was very easy – thanks, problem solved. Still I wonder why my first idea did not work…

    • Sebastian K. says:

      @Malcom: thank you too… I have to think about that.

  19. Pingback: Editbox data input validation | Undocumented Matlab

  20. Lauren says:

    Yair,

    Thanks so much for taking the time to share your Matlab expertise! I was very excited to read this, as it seems to the best solution to a problem I would like to solve. However, I haven’t been able to implement this solution, and I’m not sure why it isn’t working for me.

    Specifically, I have some edit text boxes in a GUI, and I would like to trigger a callback whenever the text is altered (without necessarily waiting for the user to click outside the edit text box), and in the callback get the current state of the text so that I can adjust some other GUI components accordingly. My problem is that the standard “callback” function doesn’t trigger the callback function until you click outside the edit text box or press enter, and the “KeyPressFcn” triggers the callback function before the ‘String’ value for the edit text box has been updated. It seems that either “KeyReleasedCallback” or “PropertyChangedCallback” might solve my problem (i.e. trigger the callback after the ‘string’ property has been changed but without requiring “enter” or an extra click).

    I attempted to implement this in the following way, but it seems that the function is not getting triggered. There is not error message, so I’m not sure what I’m doing wrong.

    (h.editTextBox is an existing edit text box in my gui)

    jbh = findobj(h.editTextBox);
    set(jbh, 'KeyReleasedCallback', @callbackFcn)
    set(jbh, 'PropertyChangedCallback', @callbackFcn)

    Thanks for any help you can provide!

    • @Lauren – my very recent article, that I have posted only a few days ago, discusses this issue exactly:
      https://undocumentedmatlab.com/blog/editbox-data-input-validation/

      Note that the article refers to single-line editboxes only – multi-line editboxes have somewhat different behavior, although the same general principles apply there as well.

      In your specific case, it is also possible that jbh returns empty for some reason, which could explain why the callbacks don’t get triggered.

  21. xay lee says:

    Hi yair! i’m trying to make a piano in matlab, (it works perfectly if its Gui keys are pressed using mouse Click), i want to change that by using my keyboard keys (all A-Z and 0-9) so it should respond by clicking any key, i have tried to do it using key press function,but in vain, it would be great if you please tell me HOW TO DO IT by some example/code snippet related to keyboard keys func. THANKS :)
    one thing more my piano gui contains 80+ keys so is it possible to use combinations like shift+A etc as well

    • @Lee – I suggest that you post your question on the CSSM newsgroup or the Matlab Answers forum.
      If you’d like my help on this as a professional consultant, please send me an offline email.

  22. Charlie says:

    Hi Yair:

    Is it possible to assign these undocumented callbacks to a previously created figure (say figure(1))?

    Best regards,

    Charlie

    • Yair Altman says:

      Yes, it is indeed possible. For previously-created uicontrols you’d need to use the findjobj function to get the underlying Java handle.

  23. Daniel says:

    Hi Yair! Thanks a lot for your research on matlab!
    I’m more or less new to matlab (not to Java) and still have some problems with the usage of handles in matlab.
    I dynamicaly create edit-boxes and use some of the underlaying java-callbacks. But in the callback function itself I need to know the handle of the matlab edit-box in order to get its UserData. The handle passed to the calback function just seems to be a handle to a java class, not an object. When I try to pass the handle of the matlab uicontrol by adding a parameter it doesn’t work properly: in some cases it works, in other the handle points to an non existing object…
    Is there a way to get the matlab uicontrol handle inside the callback function?
    Here’s my code:

    function text_ButtonDownFcn(hObject, eventdata, handles)
    % This function creates the edit-boxes. Its itself a callback from a text-label. There are plenty of these text-labels but they all refer to this callback function. The text objectes contain some infos in there UserData. These i need.
        hTextEdit = uicontrol('Style','edit','String','someText','Units','normalized','Position',pos,'UserData',hObject);
     
        % set java callbacks
        jhTextEdit = findjobj(hTextEdit);
        set(jhTextEdit,'FocusLostCallback',{@textEdit_Callback, hTextEdit});
        set(jhTextEdit,'KeyReleasedCallback',{@textEdit_KeyReleasedCallback, hTextEdit});
     
        % set focus to text-edit
        uicontrol(hTextEdit); 
    end
     
    function textEdit_Callback(hObject, eventdata, hTextEdit)
        hText = get(hTextEdit,'UserData');
        neededInfos = get(hText,'UserData'); %  get; Invalid handle object; Why, the text object still exists!
    end

    thanks a lot!

    • @Daniel – you’re basically doing it correctly, but you can pass hObject as a separate parameter rather than go through UserData:

      set(jhTextEdit,'FocusLostCallback',{@textEdit_Callback, hTextEdit, hObject});
       
      function textEdit_Callback(hObject, eventdata, hTextEdit, hText)  % hText=hObject
          ...
      end

      The important point is that this handle (and its associated control) must exist when you try to access them.

    • Daniel says:

      Okay, my fault. The text-label is destroyed and recreated. So nevermind!

      But it would be great to know it anyway: Is there a way to get the matlab uicontrol handle inside the callback function without passing it mayself?

    • Daniel says:

      Wow, you’re fast!
      Thanks for your reply!

  24. Pingback: Matlab callbacks for Java events in R2014a | Undocumented Matlab

  25. Sven says:

    Hi Yair,

    first of all thank you for the great Job you are doing on MATLAB secrets for years now!

    I’ve got the following problem when using handles in R2013b:

    I am trying to develop a small tool for analyzing stored figures. A first step would be to react on a customer mouse click.

    I did this the following way:

    figure();
    plot(1:10);
    javaFrame = get(gcf, 'JavaFrame');
    hf = handle(javaFrame.fHG1Client.getAxisComponent, 'CallbackProperties')
    set(hf,'MouseClickedCallback',@ImageClickCallback);

    Everything works fine, the output of hf is

    hf =
    	javahandle_withcallbacks.com.mathworks.hg.peer.FigureAxisComponentProxy$_AxisCanvas

    BUT if I try to work the same way with a stored figure, which I open by calling “openfig()” the following occurs:

    hf =
    	javahandle.com.mathworks.hg.peer.FigureAxisComponentProxy$_AxisCanvas
     
    Error using javahandle.com.mathworks.hg.peer.FigureAxisComponentProxy$_AxisCanvas/set
    The name 'MouseClickedCallback' is not an accessible property for an instance of class
    'com.mathworks.hg.peer.FigureAxisComponentProxy$_AxisCanvas'.

    So my question is, how is it possible to make the handle returned by the openfig()-function a “javahandle_withcallbacks”????

    Thanks a lot!

    Regards
    Sven

    • @Sven – I can’t think of an immediate solution. Once the _AxisCanvas object is created by openfig without the callbacks, you cannot add them later (see relevant comment within the javacomponent.m file.

      As an alternative, try using Matlab’s standard ButtonDownFcn callback. This might remove the need for using _AxisCanvas altogether.

  26. Pingback: Can't get mouse callback to work with java swing - BlogoSfera

  27. Pingback: Can’t get mouse callback to work with java swing | Solutions for enthusiast and professional programmers

  28. Pingback: How to capture key press in Matlab uipanel - DexPage

  29. Pingback: Error setting 'text' property of a Matlab uicontrol using its Java handle - BlogoSfera

  30. Loops says:

    Hi Yair
    Are there any callback controls in axes?
    I want monitor “PropertyCahnged” event.
    Or, re-create a class for axes?
    Thanks

    • @Loops – axes are not uicontrols and they have an entirely different set of properties, events and callbacks. Search this blog for specific axes keywords and maybe you will find what you need.

  31. Efraim says:

    Hi!
    Is there a callback function for the dropdown menu (popup) uicontrol, to execute only when one of the items is selected by the mouse or when the ‘enter’ button is pressed? The normal callback function executes with every keyboard press but I only want it to start executing when one of the items is selected (either by means of a ‘enter’ or a mouse click).

    Many thanks in advance!

    • Use the ActionPerformedCallback

    • Efraim says:

      Hi Yair,
      Thanks for your suggestion. I tried but it didn’t work the way I want it.
      Here’s an example.

      f=figure;
      u=uicontrol('style','popup','string',{'one','two','three','four'});
      jo=findjobj(u);
      jbh=handle(jo,'CallbackProperties');
      set(jbh,'ActionPerformedCallback','disp(123);')

      If I’d type ‘t’ it would select ‘two’ (and show 123 in the command line). But I don’t want it to show 123 just yet, only if I press enter, or if I had selected one of the items using the mouse.
      Hope it’s more clear!

    • There is no specific Java callback that does exactly what you want as far as I know. You can possibly achieve this functionality by programmatic logic using a combination of the existing callbacks.

  32. Noah says:

    Yair,

    Is there a generic way to pass a Matlab method to Java (that Java can execute) without having to use JFrame?
    e.g.

    classdef HelloWorld
       method
          function this = HelloWorld()
            %Pass HelloWorld.jar main entry point HellowWorld callback method
            a = HelloWorld;
            %Notional (here main is any HelloWorld class method, not limited to a JFrame callback)
            set(a,'main',{@this.callback,parm1,parm2,...})
          end
       end
       method
          function callback(parm1, parm2,...)
             ...
          end
       end
    end

    If this is do-able I’d be willing to donate numerous coffee’s :)

    Thanks in advance,
    Noah

    • @Noah – yes, this is indeed possible but the Java class would need to be written in a specific way to enable Matlab callbacks for the Java events. Contact me offline (altmany at gmail) for assistance.

  33. Nipurn Jain says:

    How to determine cursor position in ‘edit’ uicontrol?

    I have an application where there are several buttons that apply a specific function to the data. The user can also enter values in the edit box. However if the cursor is positioned in the edit box and a button is pressed the new function will appear at the end of the edit box and I need that this appear at cursor position how to do this?
    Is it possible by using javaframe available on matlab?

    • Nipurn Jain says:

      I have an application where there are several buttons that apply a specific function to the data. The user can also enter values in the edit box. However if the cursor is positioned in the edit box and a button is pressed the new function will appear at the end of the edit box and I need that this appear at cursor position how to do this?

Leave a Reply

Your email address will not be published. Required fields are marked *