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

Detecting window focus events

September 9, 2009 41 Comments

A CSSM reader recently asked whether it is possible to detect window focus events (specifically, the focus-gain event) asynchronously, so that such events can trigger a callback without necessitating a polling thread to constantly monitor the windows state.
The user correctly mentioned the fact that although mouse-clicks within the window frame can be detected using the documented figure callback WindowButtonDownFcn, there are other methods by which a window can gain focus: keyboard (<Alt>-<Tab> on Windows, for example), clicking the window frame edge etc. These methods are all undetected by WindowButtonDownFcn.
This problem is, to the best of my knowledge, insoluble using standard documented Matlab. However, there is indeed a simple solution using undocumented/unsupported Matlab features. The solution relies on the fact that all Matlab windows are basically Java Swing objects, and these objects have dozens of standard callback hooks that can be utilized (Matlab only exposes a few callbacks). The list of standard Swing callbacks was detailed in my earlier article about uicontrol callbacks, which is also relevant for Java window frames.
In this specific case, we are interested in FocusGainedCallback. This callback is invoked for the figure Frame’s AxisComponent (a part of the Frame that will be explained in another article). For each of our monitored figure windows, we set this callback to a predefined Matlab function. We may also wish to set its companion FocusLostCallback.
Here’s the resulting code snippet (hFig is our Matlab figure handle):

% Prepare the figure
hFig = figure;  % etc. - prepare the figure
% Get the underlying Java reference
warning off MATLAB:HandleGraphics:ObsoletedProperty:JavaFrame
jFig = get(hFig, 'JavaFrame');
jAxis = jFig.getAxisComponent;
% Set the focus event callback
set(jAxis,'FocusGainedCallback',{@myMatlabFunc,hFig});
% perhaps also set the FocusLostCallback here

% Prepare the figure hFig = figure; % etc. - prepare the figure % Get the underlying Java reference warning off MATLAB:HandleGraphics:ObsoletedProperty:JavaFrame jFig = get(hFig, 'JavaFrame'); jAxis = jFig.getAxisComponent; % Set the focus event callback set(jAxis,'FocusGainedCallback',{@myMatlabFunc,hFig}); % perhaps also set the FocusLostCallback here

Whenever any of the monitored figures now gets focus, by whichever means, the user-defined Matlab function myMatlabFunc() will be invoked. This function should be defined as follows:

function myMatlabFunc(jAxis, jEventData, hFig)
   % do whatever you wish with the event/hFig information
end

function myMatlabFunc(jAxis, jEventData, hFig) % do whatever you wish with the event/hFig information end

Extra input parameters can be added during callback setup and definition, as follows:

set(jAxis,'FocusLostCallback',{@myMatlabFunc,hFig,data1,data2})
...
function myMatlabFunc(jAxis, jEventData, hFig, data1, data2)
   % do whatever you wish with the event/hFig/data information
end

set(jAxis,'FocusLostCallback',{@myMatlabFunc,hFig,data1,data2}) ... function myMatlabFunc(jAxis, jEventData, hFig, data1, data2) % do whatever you wish with the event/hFig/data information end

A very similar technique can detect other windowing events (maximization/minimization/movement etc.). Depending on the case, you may need to use jFig.fFigureClient.getWindow instead of jFig.getAxisComponent. The list of available callbacks for each of these objects can be seen using a simple set(jFig.getAxisComponent) command, or via my UIInspect or FindJObj utilities on the Matlab File Exchange.
Note that all this relies on the undocumented hidden figure property JavaFrame, which issues a standing warning (since Matlab release R2008a) of becoming obsolete in some future Matlab release. Since it worked so far, I have turned off this warning in the code above, but note that this code may well fail in some future Matlab version. If and when JavaFrame does become obsolete, be sure to look in this blog for workarounds…
Addendum Aug 21, 2015: In in HG2 (R2014b onward), setting the Focus events (FocusGained, FocusLost etc.) on the AxisComponent does not work. Instead, we can simply set the callbacks on the AxisComponent’s direct child, as follows:

set(jAxis.getComponent(0),'FocusGainedCallback',{@myMatlabFunc,hFig});

set(jAxis.getComponent(0),'FocusGainedCallback',{@myMatlabFunc,hFig});

Related posts:

  1. Fixing a Java focus problem – Java components added to Matlab GUIs do not participate in the standard focus cycle - this article explains how to fix this problem....
  2. Transparent Matlab figure window – Matlab figure windows can be made fully or partially transparent/translucent or blurred - 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. Enable/disable entire figure window – Disabling/enabling an entire figure window is impossible with pure Matlab, but is very simple using the underlying Java. This article explains how....
  5. Figure window customizations – Matlab figure windows can be customized in numerous manners using the underlying Java Frame reference. ...
  6. Blurred Matlab figure window – Matlab figure windows can be blurred using a semi-transparent overlaid window - this article explains how...
FindJObj GUI Hidden property Java JavaFrame UIInspect
Print Print
« Previous
Next »
41 Responses
  1. Donn Shull September 18, 2009 at 22:36 Reply

    I think I found this in some of your code on the MathWorks file exchange, anyway if you don’t like having to turn warnings off you can use the undocumented use of handle as a function to get the underlying figure object and access the JavaFrame property from there without generating a warning.

    hFig = figure;
    obj = handle(hFig);
    jFig = obj.JavaFrame;

    hFig = figure; obj = handle(hFig); jFig = obj.JavaFrame;

    Thanks for the great work Yair.

  2. David July 30, 2010 at 00:47 Reply

    Hi,

    I am working with a java component in matlab. I have wrapped a JTextArea and added a scroll and some features to it. I have two problems that I would like to solve:

    1) I need a callback to use when something changes in the text area. I would like to use this to implement a UNDO, crl+z, feature. Do you know a suitable callback for this?

    2) When I work with the text area it is very slow to render and repaint. If i delete some text, paste large blocks etc it might not render. I have tried calling repaint without success. Do you have a solution for this?

    -David

    • Yair Altman July 30, 2010 at 02:32 Reply

      @David – have a look here: http://undocumentedmatlab.com/blog/uicontrol-callbacks/
      I don’t have an immediate solution to the performance issue. JTextArea is usually performant, since it doesn’t have different fonts/styles like JEditorPane or JTextPane. Perhaps the bottleneck is in one of your callbacks or listeners?

    • Malcolm Lidierth May 20, 2011 at 04:34 Reply

      JText**** text edits are thread-safe: they are always run on the EDT by the Swing component’s own code. A drawnow() from MATLAB might help if the screen is not updating.

  3. Kesh August 2, 2010 at 07:41 Reply

    Hey Yair,

    It’s me again. I got a funny behavior when trying to access figure focus callbacks of saved figure. Here’s an example:

    Open a plain figure with nothing in it and get the AxisComponent properties:

    figure
    jFig = get(handle(gcf), 'JavaFrame');
    jAxis = jFig.getAxisComponent;
    get(jAxis)

    figure jFig = get(handle(gcf), 'JavaFrame'); jAxis = jFig.getAxisComponent; get(jAxis)

    returns what we expect:

    	UIJGraphics = []
    	AccessibleContext = [ (1 by 1) java.awt.Canvas$AccessibleAWTCanvas array]
    	Background = [0.92549 0.913725 0.847059]
    	BufferStrategy = []
    	Component = [ (1 by 1) com.mathworks.hg.peer.FigureAxisComponentProxy$_AxisCanvas array]
    	ComponentLightweight = off
    	Enabled = on
    	Focusable = on
    	Font = [ (1 by 1) javax.swing.plaf.FontUIResource array]
    	Foreground = [0 0 0]
    	Graphics = [ (1 by 1) com.mathworks.hg.peer.AxisCanvas$HGDebugGraphics array]
    	Name = fAxisComponentProxy
    	NativeWindowHandle = [0]
    	NativeWindowHandleValid = off
    	MouseWheelMovedCallback = 
    	MouseWheelMovedCallbackData = []
     
    	KeyTypedCallback = 
    	KeyTypedCallbackData = []
     
    	BeingDeleted = off
    	ButtonDownFcn = 
    	Children = []
    	Clipping = on
    	CreateFcn = 
    	DeleteFcn = 
    	BusyAction = queue
    	HandleVisibility = on
    	HitTest = on
    	Interruptible = on
    	Parent = []
    	Selected = off
    	SelectionHighlight = on
    	Tag = 
    	Type = com.mathworks.hg.peer.FigureAxisComponentProxy$_AxisCanvas
    	UIContextMenu = []
    	UserData = []
    	Visible = on

    UIJGraphics = [] AccessibleContext = [ (1 by 1) java.awt.Canvas$AccessibleAWTCanvas array] Background = [0.92549 0.913725 0.847059] BufferStrategy = [] Component = [ (1 by 1) com.mathworks.hg.peer.FigureAxisComponentProxy$_AxisCanvas array] ComponentLightweight = off Enabled = on Focusable = on Font = [ (1 by 1) javax.swing.plaf.FontUIResource array] Foreground = [0 0 0] Graphics = [ (1 by 1) com.mathworks.hg.peer.AxisCanvas$HGDebugGraphics array] Name = fAxisComponentProxy NativeWindowHandle = [0] NativeWindowHandleValid = off MouseWheelMovedCallback = MouseWheelMovedCallbackData = [] KeyTypedCallback = KeyTypedCallbackData = [] BeingDeleted = off ButtonDownFcn = Children = [] Clipping = on CreateFcn = DeleteFcn = BusyAction = queue HandleVisibility = on HitTest = on Interruptible = on Parent = [] Selected = off SelectionHighlight = on Tag = Type = com.mathworks.hg.peer.FigureAxisComponentProxy$_AxisCanvas UIContextMenu = [] UserData = [] Visible = on

    But, when this figure is saved and loaded again:

    hgsave test
    hgload test
     
    jFig1 = get(handle(gcf), 'JavaFrame');
    jAxis1 = jFig1.getAxisComponent;
    get(jAxis1)

    hgsave test hgload test jFig1 = get(handle(gcf), 'JavaFrame'); jAxis1 = jFig1.getAxisComponent; get(jAxis1)

    Now, AxisComponent properties are crippled:

                    UIJGraphics: []
              AccessibleContext: [1x1 java.awt.Canvas$AccessibleAWTCanvas]
                     Background: [1x1 javax.swing.plaf.ColorUIResource]
                 BufferStrategy: []
                      Component: [1x1 com.mathworks.hg.peer.FigureAxisComponentProxy$_AxisCanvas]
           ComponentLightweight: 0
                        Enabled: 1
                      Focusable: 1
                           Font: [1x1 javax.swing.plaf.FontUIResource]
                     Foreground: [1x1 javax.swing.plaf.ColorUIResource]
                       Graphics: [1x1 com.mathworks.hg.peer.AxisCanvas$HGDebugGraphics]
                           Name: 'fAxisComponentProxy'
             NativeWindowHandle: 0
        NativeWindowHandleValid: 0

    UIJGraphics: [] AccessibleContext: [1x1 java.awt.Canvas$AccessibleAWTCanvas] Background: [1x1 javax.swing.plaf.ColorUIResource] BufferStrategy: [] Component: [1x1 com.mathworks.hg.peer.FigureAxisComponentProxy$_AxisCanvas] ComponentLightweight: 0 Enabled: 1 Focusable: 1 Font: [1x1 javax.swing.plaf.FontUIResource] Foreground: [1x1 javax.swing.plaf.ColorUIResource] Graphics: [1x1 com.mathworks.hg.peer.AxisCanvas$HGDebugGraphics] Name: 'fAxisComponentProxy' NativeWindowHandle: 0 NativeWindowHandleValid: 0

    The callback fields are no longer accessible among many others. Do you know why this happens and/or how to work around this problem to get to the focus callbacks?

    TIA

    • Kesh August 2, 2010 at 07:43 Reply

      Oops, I mistakenly placed “” text in MATLAB code block. For the first get(jAxis) returned values, there are many other Callback Fields between “MouseWheelMovedCallbackData = []” and ” KeyTypedCallback = “

      • Yair Altman August 5, 2010 at 11:01

        @Kesh – this is an undocumented bug in the way Matlab loads FIG files – it loads Java objects without the ‘CallbackProperties’ argument (or some equivalent action), causing the object’s callbacks not to be visible in Matlab.

        Apparently, only GUI figures and components created in run-time have accessible callbacks. This sounds odd, and I would love to learn how to bypass this limitation, but at the moment I don’t know if this is possible.

      • Kesh August 5, 2010 at 11:59

        That’s a bummer. I wonder if there is any way for us to “attach” CallbackProperties after FIG is loaded… If you learn a way around for it, please let me know!

      • Donn August 7, 2010 at 12:13

        @Kesh – Even though the callback properties are not available the corresponding events are still generated. You can create listeners to them with:

           l = handle.listener(handle(jAxis), 'FocusGained', @callback)

        l = handle.listener(handle(jAxis), 'FocusGained', @callback)

        It is not as convienent as the callback properties, but it works.

      • Kesh August 9, 2010 at 10:22

        @Donn, thanks for the tip! That’ll do for me.

  4. per isakson October 21, 2010 at 12:23 Reply

    Hello Yair,

    This function to detect when a figure gain focus is tempting to use and I tried it. However, I run into one problem with clearing objects. causes a burst of
    “Warning: Objects of ‘xyz’ class exist. Cannot clear this class or any of its super-classes.”

    I use your code in a method of a class. The function invoked by the event is a nested function defines in the same method.

    This might not be a big problem once the my code is correct. However, during debugging it forces me to restart Matlab often. Changes in my classes are not used unless the old object are cleared.

    Is there a work around – or did I miss something?

    Best regards
    per

    • Yair Altman October 21, 2010 at 13:19 Reply

      @per – This happens because the Java object (jAxis) keeps a reference to your class and so the class cannot be cleared. Try closing all relevant figure windows and/or using clear java before you attempt to clear the Matlab class instances.

      Alternately, you can use the handle.listener approach suggested by Donn Shull above. You may possibly need to delete all the listener handles before clearing the Matlab class instances, but it may even work without these deletions.

      Please let us all know if any of these tricks actually solved the problem.
      -Yair

      • per isakson October 22, 2010 at 07:16

        @Yair – No, clear classes still triggers the burst of warnings.

        Now, I have tried the construct that you propose in the post, the variant proposed by Donn Shull and the handle.listener approach (see code snippet below) also proposed by Donn Shull. In all three cases my nested function, FocusGained, is called when I click on the figure. Deleting the figure and applying clear java, clear all, clear classes (with and without lear all) after each of the three puts Matlab into an “unexpected” state: inmem reports an “empty” memory and clear classes produces the burst of warnings. See below.

        >> inmem
        ans = 
            'workspacefunc'
        >> clear classes
        Warning: Objects of 'SpringHarp' class exist.  Cannot clear this class or any of its super-classes. 
        Warning: Objects of 'Editbox' class exist.  Cannot clear this class or any of its super-classes. 
        etc.

        >> inmem ans = 'workspacefunc' >> clear classes Warning: Objects of 'SpringHarp' class exist. Cannot clear this class or any of its super-classes. Warning: Objects of 'Editbox' class exist. Cannot clear this class or any of its super-classes. etc.

        Below is an excerpt from a method of the class. I tried with and without the line “this”, which is the internal name of th object. That does not make any difference. I still have to create the jAxis object or did I miss something?

        jFig = get( handle( this.hgh ), 'JavaFrame');
        jAxis = jFig.getAxisComponent;           
        hListener = handle.listener( handle( jAxis ) , 'FocusGained', { @FocusGained, 'kk' } );
        %
        function    FocusGained( varargin )    
           this;
           y=1;%#ok    
           z=1;%#ok
        end

        jFig = get( handle( this.hgh ), 'JavaFrame'); jAxis = jFig.getAxisComponent; hListener = handle.listener( handle( jAxis ) , 'FocusGained', { @FocusGained, 'kk' } ); % function FocusGained( varargin ) this; y=1;%#ok z=1;%#ok end

        Shot in the dark

        % jFig = get( handle( this.hgh ), 'JavaFrame');
        % jAxis = jFig.getAxisComponent;           
        hListener = handle.listener( handle( this.hgh ), 'FocusGained', { @FocusGained, 'kk' } );

        % jFig = get( handle( this.hgh ), 'JavaFrame'); % jAxis = jFig.getAxisComponent; hListener = handle.listener( handle( this.hgh ), 'FocusGained', { @FocusGained, 'kk' } );

        this.hgh is the figure handle graphic handle. This did not cause any errors or warnings, but clicking the figure did not trigger the callback. This also left the Matlab with inmem reporting empty and clear classes causing the burst of warnings.

        / per

        PS. I run R2010a on Windows 7 both with 64bit.

      • per isakson October 22, 2010 at 12:12

        @Yair – I should have known better than testing with a nested function!

        Now, I have tested a with a subfunctions as callbackfunction, i.e. moved the function, FocusGained, to after the end of classdef. The object, named this, is passed as an argument.

         set( jax, 'FocusGainedCallback', { @FocusGained, this } );

        set( jax, 'FocusGainedCallback', { @FocusGained, this } );

        The problem remains with the construct that you propose in the post, including with the variant proposed by Donn Shull. However, the handle.listener approach seems to work, i.e. clear classes clears the objects. There is no burst of warnings. clear java is not needed.

        / per

  5. Yair Altman October 23, 2010 at 09:02 Reply

    Interesting difference. Thanks for sharing, Per
    -Yair

  6. Jamil Onaran April 5, 2011 at 13:13 Reply

    Hi Donn
    The below code did not work for the loaded figure, unlike the FocusGained callback. Is there another work around for this problem.

    hgsave test
    hgload test
     
    jFig1 = get(handle(gcf), 'JavaFrame');
    jAxis1 = jFig1.getAxisComponent;
    l = handle.listener(handle(jAxis1),'MouseMovedCallback',@(a,b) disp('ab'))

    hgsave test hgload test jFig1 = get(handle(gcf), 'JavaFrame'); jAxis1 = jFig1.getAxisComponent; l = handle.listener(handle(jAxis1),'MouseMovedCallback',@(a,b) disp('ab'))

    Thanks

    • Yair Altman April 5, 2011 at 15:01 Reply

      @Jamil – this may be the same issue as Kesh mentioned in comments above – please see my answer there. In short, Java callbacks don’t work as advertised for hgloaded figures – only for figures created in runtime. This appears to be due to an internal Matlab bug, but I would not hold my breath for it to be fixed…

      Try using Donn’s suggested workaround of using UDD’s handle.listener function, which are explained in detail in this article.

      • Donn Shull April 5, 2011 at 19:46

        @Jamil – Note that when using handle.listener you need to use the event name which in your case is ‘MouseMoved’ rather than the callback property name which is ‘MouseMovedCallback’.

        hgsave test
        hgload test
         
        jFig1 = get(handle(gcf), 'JavaFrame');
        jAxis1 = jFig1.getAxisComponent;
        l = handle.listener(handle(jAxis1),'MouseMoved',@(a,b) disp('ab'))

        hgsave test hgload test jFig1 = get(handle(gcf), 'JavaFrame'); jAxis1 = jFig1.getAxisComponent; l = handle.listener(handle(jAxis1),'MouseMoved',@(a,b) disp('ab'))

      • Jamil Onaran April 5, 2011 at 22:56

        Thanks,
        I figured it out.
        toolbox\matlab\uitools\@uitools\@uimode\createuimode.m file cuases this problem, here is the corresponding code. The callbacks are usable until this line.

            hAxisComponent = handle(hFrame.getAxisComponent);

        hAxisComponent = handle(hFrame.getAxisComponent);

        If you use get function for the axis component before this line or set the figure visible, the callbacks would be working. I don’t exactly know what handle is doing on invisible figures.

      • Jamil Onaran April 6, 2011 at 00:58

        Hi again,
        Actually this is not a visibility issue.
        I have a test code below, using handles on AxisComponent will cause this error if we try to install a a callback.

        %% Create a new figure
        close all
        hFig = figure;
        %% Run this to generate an error
        Frame  = get(hFig,'JavaFrame');
        hFrame = handle(Frame);
        hAxisComponent = handle(hFrame.getAxisComponent);
        %% Get java frame and install a callback
        Frame  = get(hFig,'JavaFrame');
        AxisComponent = Frame.getAxisComponent;
        set(AxisComponent,'MouseMovedCallback',@(a,b) disp('MMC'))

        %% Create a new figure close all hFig = figure; %% Run this to generate an error Frame = get(hFig,'JavaFrame'); hFrame = handle(Frame); hAxisComponent = handle(hFrame.getAxisComponent); %% Get java frame and install a callback Frame = get(hFig,'JavaFrame'); AxisComponent = Frame.getAxisComponent; set(AxisComponent,'MouseMovedCallback',@(a,b) disp('MMC'))

      • Donn Shull April 6, 2011 at 08:16

        @Jamil – To summarize: To have callback properties the UDD peer must be created in the javahandle_withcallbacks package. In your code above you should use:

        Frame  = get(hFig,'JavaFrame', 'CallbackProperties');

        Frame = get(hFig,'JavaFrame', 'CallbackProperties');

        Then you will not generate errors. As Yair has explained hgload will create the UDD peer in the javahandle package which does not have callback properties. If you wish to use hgsave and hgload then you should design your code using handle.listener to process events. You need to take care to use the proper event names and provide persistent storage for your listener objects.

        Donn

      • Jamil Onaran April 11, 2011 at 04:37

        Hi Donn,
        I got it, but I just demonstrated what createuimode.m does to disable the callback of axis component. After calling handle function for axisComponenent, we can not assign any callback to AxisCompnent. But your method works perfect and solved my problem. I’m using the following code to get the axisComponent.

        mde = com.mathworks.mde.desk.MLDesktop.getInstance;
        figName = get(hObject,'name');
        if strcmpi(get(hObject,'number'),'on')
            figName = regexprep(['Figure ' num2str(hObject) ': ' figName],': $','');
        end
        jFig = []; iTry = 10;
        while isempty(jFig) &amp;&amp; iTry
            jFig = mde.getClient(figName);
            iTry = iTry-1;
            pause(0.1);
        end
        axisComponent = jFig.getComponent(0).getComponent(0).getComponent(1);
        axisComponent = handle(axisComponent, 'CallbackProperties');

        mde = com.mathworks.mde.desk.MLDesktop.getInstance; figName = get(hObject,'name'); if strcmpi(get(hObject,'number'),'on') figName = regexprep(['Figure ' num2str(hObject) ': ' figName],': $',''); end jFig = []; iTry = 10; while isempty(jFig) &amp;&amp; iTry jFig = mde.getClient(figName); iTry = iTry-1; pause(0.1); end axisComponent = jFig.getComponent(0).getComponent(0).getComponent(1); axisComponent = handle(axisComponent, 'CallbackProperties');

        This is an alternative method to get the axis component, but we can not obtain JavaFrame object from this code. I wish Matlab won’t stop supporting the javaframe.
        Do you have other work arounds if they do so?

  7. Jamil Onaran April 11, 2011 at 04:41 Reply

    There should be a way to delete modify these comment, is there a way that I don’t know?

    • Yair Altman April 11, 2011 at 05:46 Reply

      @Jamil – unfortunately, the current website design does not enable comment modification/deletion…

  8. julien June 8, 2012 at 13:49 Reply

    Hi !
    I would like to launch a callback when mouse enters or exits a figure. This can be achieved by setting MouseEnteredCallback and MouseExitedCallback on axisComponent. However, when figure’s contentPane is completely filled with controls (uicontrols or JComponents), this does not work any more. If I well understand, this is because components’ panel is above axisComponent.
    Is there another way to detect when mouse enters or exits a figure ? I played around with other JavaFrame hierarchy containers, but I did not find a solution.
    I could set all components MouseEnteredCallback and triggers my callback when figure has not the focus but this is rather heavy…
    Would you have another idea?

    • Malcolm Lidierth June 9, 2012 at 06:37 Reply

      You may find the MouseMotionHandler class in Project Waterloo does what you need.

      It uses the standard TMW WindowButtonMotion callback as a hook but discriminates between mouse exits, enters and moves using internal logic. You can still use MouseEnteredCallbacks, ButtonDownCallbacks etc in tandem.

      • julien June 9, 2012 at 13:56

        Thanks for your help, Malcolm. This is a good solution indeed, except when the figure is populated with JComponents (with javacomponent function) for which WindowButtonMotionFcn is not executed when mouse moves over them…
        However, your MouseMotionHandler class is a very nice utility!

  9. Bluesmaster April 19, 2013 at 11:08 Reply

    Is it possible to listen to minimized/ maximized events
    I tried a lot but why this task is so much more difficult than mousemove or focus etc?

    regards

    Bluesmaster

    • Yair Altman April 20, 2013 at 10:25 Reply

      @Bluemaster – yes, this is possible. I discuss it in Section 7.3.7 of my Matlab-Java programming book. Specifically, look at the WindowIconifiedCallback and WindowDeiconifiedCallback properties of the FigureFrame proxy object.

      • Bluesmaster April 20, 2013 at 13:59

        Thank you so much.

        For anyone whos interested (if it is ok?): the ‘javaframe’ is not enough:

        f = figure;
        j = get( f , 'javaframe' );
        drawnow;
        w = j.fHG1Client.getWindow();
         
        set( w , 'WindowIconifiedCallback'   , @(~,~) disp('WindowIconifiedCallback')   );
        set( w , 'WindowDeiconifiedCallback' , @(~,~) disp('WindowDeiconifiedCallback') );

        f = figure; j = get( f , 'javaframe' ); drawnow; w = j.fHG1Client.getWindow(); set( w , 'WindowIconifiedCallback' , @(~,~) disp('WindowIconifiedCallback') ); set( w , 'WindowDeiconifiedCallback' , @(~,~) disp('WindowDeiconifiedCallback') );

  10. SA July 24, 2013 at 02:33 Reply

    Any idea if it is possible to intercept existing callbacks? I’d be interested in disabling matlabs’ ability to change the currentfigure setting when it receives mouse focus. I would like to return to the old behaviour where figure() sets the currentfigure and the mouse doesn’t.

    • SA July 24, 2013 at 02:45 Reply

      Can I modify the question – I’d like to capture all focus events for all figures (then I can reset “currentfigure”). Is there a way to do this?

      • SA July 24, 2013 at 03:41

        Solution found – thanks for undoc’d documentation – brilliant.

        (1) overload figure.m (place this function in your path)

        %% fix the annoying focus follows mouse bug
        %% (c) GPL SA 2013
        function h=figure(n);
            global hasfocus;
            if(~exist('n'))
                n=1;
                end;
            h = builtin('figure',n);
            jFig = get(h,'JavaFrame');
            jAxis = jFig.getAxisComponent;
            set(jAxis,'FocusGainedCallback',{@setfocus,h});
            hasfocus = h;

        %% fix the annoying focus follows mouse bug %% (c) GPL SA 2013 function h=figure(n); global hasfocus; if(~exist('n')) n=1; end; h = builtin('figure',n); jFig = get(h,'JavaFrame'); jAxis = jFig.getAxisComponent; set(jAxis,'FocusGainedCallback',{@setfocus,h}); hasfocus = h;

        (2) catch the mouse focus events (place this function in your path)

        %% fix the annoying focus follows mouse bug
        %% (c) GPL SA 2013
        function setfocus(jAxis, jEventData, hFig)
            global hasfocus;
            set(0,'currentfigure',hasfocus)
        end

        %% fix the annoying focus follows mouse bug %% (c) GPL SA 2013 function setfocus(jAxis, jEventData, hFig) global hasfocus; set(0,'currentfigure',hasfocus) end

        (3) If you are bothered by warning messages spamming up your console put this line in your matlab start up files:

        warning off MATLAB:dispatcher:nameConflict

        warning off MATLAB:dispatcher:nameConflict

        Works for me on matlab 2007something

  11. Paul Andrews February 12, 2015 at 11:51 Reply

    Dear all,

    The mechanism described above for detecting windows focus event does not work in R2014b. I believe the issue is related in changes in the figure’s AxisComponent. In R2013b, jFrame.getAxisComponent returns:

    com.mathworks.hg.peer.FigureAxisComponentProxy$_AxisCanvas[fAxisComponentProxy,0,0,560x420]

    com.mathworks.hg.peer.FigureAxisComponentProxy$_AxisCanvas[fAxisComponentProxy,0,0,560x420]

    In R2014b, it returns:

    com.mathworks.hg.peer.HeavyweightLightweightContainerFactory$FigurePanelContainerLight[fFigurePanel,0,0,560x420,layout=...]

    com.mathworks.hg.peer.HeavyweightLightweightContainerFactory$FigurePanelContainerLight[fFigurePanel,0,0,560x420,layout=...]

    If you have a solution for this problem, please post it.

    Paul

    % Snippet used to test focus callbacks
    hFig = figure('name', 'FocusGainTest');  % etc. - prepare the figure
     
    % Get the underlying Java reference
    warning off MATLAB:HandleGraphics:ObsoletedProperty:JavaFrame
    jFrame = get(hFig, 'JavaFrame');
    hFrame = handle(jFrame,'CallbackProperties');
     
    jAxis = jFrame.getAxisComponent 
    hAxis = handle(jAxis,'CallbackProperties');
     
    % Set the focus event callback
    set(hAxis,'FocusGainedCallback', @(a,b) disp('FocusGainedCallback'));
    set(hAxis,'FocusLostCallback', @(a,b) disp('FocusLostCallback'));

    % Snippet used to test focus callbacks hFig = figure('name', 'FocusGainTest'); % etc. - prepare the figure % Get the underlying Java reference warning off MATLAB:HandleGraphics:ObsoletedProperty:JavaFrame jFrame = get(hFig, 'JavaFrame'); hFrame = handle(jFrame,'CallbackProperties'); jAxis = jFrame.getAxisComponent hAxis = handle(jAxis,'CallbackProperties'); % Set the focus event callback set(hAxis,'FocusGainedCallback', @(a,b) disp('FocusGainedCallback')); set(hAxis,'FocusLostCallback', @(a,b) disp('FocusLostCallback'));

    • Yvon Halbwachs August 20, 2015 at 23:10 Reply

      Paul, I’m facing the same problem as you have in R2014b. By any chance, did you find any solution to this?

      Yvon

    • Yair Altman August 21, 2015 at 00:19 Reply

      @Paul & @Yvon – in HG2 (R2014b onward), you can simply set the Focus events (FocusGained, FocusLost etc.) on the direct child of the AxisComponent, as follows:

      set(jAxis.getComponent(0),'FocusGainedCallback',{@myMatlabFunc,hFig});

      set(jAxis.getComponent(0),'FocusGainedCallback',{@myMatlabFunc,hFig});

  12. Fabio January 19, 2017 at 19:13 Reply

    It seem as the callbacks don’t work when an axes is inside the figure (as said also here: https://it.mathworks.com/matlabcentral/answers/284809-focusgainedcallback-doesn-t-work-once-figure-has-axes-2015b ), any solution? Thanks in advance

    • Daniel Castano February 15, 2017 at 18:59 Reply

      Same problem here πŸ™ … so frustrating, as other callbacks as for instance:

      set(jAxis.getComponent(0),'MouseMovedCallback',@(x,y)disp('ab'));

      set(jAxis.getComponent(0),'MouseMovedCallback',@(x,y)disp('ab'));

      work fine after adding axes to the figure. I really hope that somebody comes up with a solution.

    • Daniel Castano February 16, 2017 at 11:41 Reply

      Well, I found a solution (R2016b) by trial and error for very simple situations, i.e., just one axes inside the figure.
      I just check the number of components in jAxis and grab the last one.

      hFig = figure; 
      h = axes(hFig);
      plot(rand(100,1),'Parent',h);
      jFig = get(hFig, 'JavaFrame');
      jAxis = jFig.getAxisComponent;
       
      n = jAxis.getComponentCount;
      disp(n);
      jAxis.grabFocus();
      drawnow; % will not work without this
      n = jAxis.getComponentCount;
      disp(n);
       
      set(jAxis.getComponent(n-1),'FocusGainedCallback',@(x,y)disp('in focus'));
      set(jAxis.getComponent(n-1),'FocusLostCallback',  @(x,y)disp('... out'));

      hFig = figure; h = axes(hFig); plot(rand(100,1),'Parent',h); jFig = get(hFig, 'JavaFrame'); jAxis = jFig.getAxisComponent; n = jAxis.getComponentCount; disp(n); jAxis.grabFocus(); drawnow; % will not work without this n = jAxis.getComponentCount; disp(n); set(jAxis.getComponent(n-1),'FocusGainedCallback',@(x,y)disp('in focus')); set(jAxis.getComponent(n-1),'FocusLostCallback', @(x,y)disp('... out'));

      Note that this is mainly cargo cult: I have no idea why I need to grab the focus and force a redraw for this to work. Still would be thankful if somebody comes up with a better, explainable solution, because the one I suggest here does not work for more complicated situations, such as GUIs with multiple panels and changing number of elements…

    • Alexander K. June 14, 2018 at 03:52 Reply
      % R2018a
      hFig = figure; 
      hAxes = axes(hFig);
      plot(rand(100,1),'Parent',hAxes);
       
      JavaSceneServerGLJPanel=get(hAxes.NodeParent.JavaComponent,'Component')
      hJavaSceneServerGLJPanel=handle(JavaSceneServerGLJPanel,'CallbackProperties');
       
      set(hJavaSceneServerGLJPanel,'FocusGainedCallback',@(x,y)disp('in focus'));
      set(hJavaSceneServerGLJPanel,'FocusLostCallback',  @(x,y)disp('... out'));

      % R2018a hFig = figure; hAxes = axes(hFig); plot(rand(100,1),'Parent',hAxes); JavaSceneServerGLJPanel=get(hAxes.NodeParent.JavaComponent,'Component') hJavaSceneServerGLJPanel=handle(JavaSceneServerGLJPanel,'CallbackProperties'); set(hJavaSceneServerGLJPanel,'FocusGainedCallback',@(x,y)disp('in focus')); set(hJavaSceneServerGLJPanel,'FocusLostCallback', @(x,y)disp('... out'));

    • Alexander K. June 14, 2018 at 08:31 Reply
      % R2018a
      hFig = figure; 
      hAxes = axes(hFig);
      plot(rand(100,1),'Parent',hAxes);
       
      % JavaSceneServerGLJPanel=get(hAxes.NodeParent.JavaComponent,'Component')
      % hJavaSceneServerGLJPanel=handle(JavaSceneServerGLJPanel,'CallbackProperties');
      %  
      % set(hJavaSceneServerGLJPanel,'FocusGainedCallback',@(x,y)disp('in focus'));
      % set(hJavaSceneServerGLJPanel,'FocusLostCallback',  @(x,y)disp('... out'));
       
      drawnow
       
      jf=get(hFig,'JavaFrame');
      jw=handle(jf.getFigurePanelContainer.getTopLevelAncestor,'CallbackProperties');
       
      set(jw,'WindowGainedFocusCallback',@(x,y)disp('in focus'));
      set(jw,'WindowLostFocusCallback',  @(x,y)disp('... out'));

      % R2018a hFig = figure; hAxes = axes(hFig); plot(rand(100,1),'Parent',hAxes); % JavaSceneServerGLJPanel=get(hAxes.NodeParent.JavaComponent,'Component') % hJavaSceneServerGLJPanel=handle(JavaSceneServerGLJPanel,'CallbackProperties'); % % set(hJavaSceneServerGLJPanel,'FocusGainedCallback',@(x,y)disp('in focus')); % set(hJavaSceneServerGLJPanel,'FocusLostCallback', @(x,y)disp('... out')); drawnow jf=get(hFig,'JavaFrame'); jw=handle(jf.getFigurePanelContainer.getTopLevelAncestor,'CallbackProperties'); set(jw,'WindowGainedFocusCallback',@(x,y)disp('in focus')); set(jw,'WindowLostFocusCallback', @(x,y)disp('... out'));

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 (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
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) uitable (6) uitools (20) Undocumented feature (187) Undocumented function (37) Undocumented property (20)
Recent Comments
Contact us
Captcha image for Custom Contact Forms plugin. You must type the numbers shown in the image
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