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

Matlab callbacks for Java events in R2014a

May 8, 2014 16 Comments

Exactly five years ago, in one of this blog’s first articles, I wrote an article explaining how to trap the standard Java Swing events in Matlab, in order to achieve much more extensive behavior customizability than Matlab’s standard uicontrols. Three years ago I wrote a related article showing how to trap any Java events as simple Matlab callbacks, even those from custom Java classes. This worked very well over the years, until now.
Over the past few weeks, several people have commented and emailed me about a problem that occurs in R2014a but not in earlier releases: Whereas Java objects in R2013b and earlier automatically exposed their public events as Matlab callbacks, they no longer do so in R2014a.
As a simple example to illustrate the point, let’s take a simple Java JButton and modify its label when the mouse moves over it, using the mouseEntered, mouseExited events. In R2013b and earlier this was pretty easy:

% Create and display a simple JButton
jButton = javax.swing.JButton('click me');
javacomponent(jButton, [50,50,80,20], gcf);
% Set the Matlab callbacks to the JButton's events
set(jButton, 'MouseEnteredCallback', @(h,e)set(jButton,'Text','NOW !!!'))
set(jButton, 'MouseExitedCallback',  @(h,e)jButton.setText('click me'))

% Create and display a simple JButton jButton = javax.swing.JButton('click me'); javacomponent(jButton, [50,50,80,20], gcf); % Set the Matlab callbacks to the JButton's events set(jButton, 'MouseEnteredCallback', @(h,e)set(jButton,'Text','NOW !!!')) set(jButton, 'MouseExitedCallback', @(h,e)jButton.setText('click me'))

Dynamic Matlab callback behavior based on Java events

(Note how I used two distinct variants to set the button’s text, using either the Matlabized Text property with the set function, or the standard JButton’s setText() method. We can use either of these variants: they are equivalent and largely a matter of personal taste, although the Java method is generally preferable.)
Unfortunately, in R2014a we get an error, since the jButton object no longer exposes its events as Matlab callbacks:

>> set(jButton, 'MouseEnteredCallback', @(h,e)set(jButton,'Text','NOW !!!'))
The name 'MouseEnteredCallback' is not an accessible property for an instance of class 'javax.swing.JButton'.


The solution – wrap the Java reference in a Matlab handle

Do not set Matlab callbacks on the so-called “naked” Java reference. Instead, wrap the reference with a Matlab handle:

>> jButton = handle(jButton, 'CallbackProperties');
hjButton =
	javahandle_withcallbacks.javax.swing.JButton
% we can now set the callbacks on jButton as before

>> jButton = handle(jButton, 'CallbackProperties'); hjButton = javahandle_withcallbacks.javax.swing.JButton % we can now set the callbacks on jButton as before

The simple act of using the handle wrapper rather than the naked Java reference also prevents some memory leaks, as I explained here. While you’re at it, also wrap (or more precisely, auto-delegate) the Java reference with a javaObjectEDT, if it is a Swing GUI component, in order to avoid EDT timing issues. Using these wrappers form two of my six rules for safe Java programming in Matlab, that I outlined in section 1.5 of my Matlab-Java programming book. Anyone who followed that advice would not need to modify their code for R2014a. Even if you didn’t, the solution is quite painless: simply add the wrapper line for any Java reference whose events you wish to trap.
Note that the explanation above relates to all Java objects that expose events, not just for GUI ones. I used JButton merely to illustrate the point.

Related posts:

  1. Matlab callbacks for Java events – Events raised in Java code can be caught and handled in Matlab callback functions - this article explains how...
  2. Matlab callbacks for uifigure JavaScript events – Matlab callback code can be attached to JavaScript events in web-based uifigures. ...
  3. Uicontrol callbacks – This post details undocumented callbacks exposed by the underlying Java object of Matlab uicontrols, that can be used to modify the control's behavior in a multitude of different events...
  4. Matlab-Java interface using a static control – The switchyard function design pattern can be very useful when setting Matlab callbacks to Java GUI controls. This article explains why and how....
  5. JMI – Java-to-Matlab Interface – JMI enables calling Matlab functions from within Java. This article explains JMI's core functionality....
  6. Waiting for asynchronous events – The Matlab waitfor function can be used to wait for asynchronous Java/ActiveX events, as well as with timeouts. ...
Callbacks Java Undocumented feature
Print Print
« Previous
Next »
16 Responses
  1. Donn Shull May 14, 2014 at 13:18 Reply

    This change “enforces” using callbacks in a way which prevents memory leaks. But since this was essentially undocumented all along this change opens up a more interesting question. Is this change part of under the hood reorganizations in preparation for HG2? Or possibly a movement towards aligning java support with MCOS and away from UDD?

    • Yair Altman May 14, 2014 at 13:25 Reply

      Maybe both, I don’t know…

      For the record, I miss UDD’s ability to dynamically control/add class properties (schema.prop et al) in run time. It’s causing me a lot of headaches migrating some of my code to HG2.

  2. Sean Lynch September 12, 2014 at 08:12 Reply

    I’ve just run the above example and it works without the update; Have MATLAB patched R2014a. my version reports 8.3.0.532 (R2014a)?

    Also the EventTest example does not work/without the update:

    >> evt = javaObjectEDT(nujira.EventTest)
    evt =
    nujira.EventTest@64902cf8
     
    >> evt = handle(evt, 'CallbackProperties')
    evt =
    	javahandle_withcallbacks.nujira.EventTest
     
    >> get(evt)
                        Class: [1x1 java.lang.Class]
            TestEventCallback: []
        TestEventCallbackData: []
     
    >> set(evt,'TestEventCallback',@(h,e)disp(h))
    java.lang.NullPointerException
    	at com.mathworks.jmi.bean.MatlabBeanInterface.addCallback(MatlabBeanInterface.java:484)
    	at com.mathworks.jmi.bean.MatlabCallbackInterface.addCallback(MatlabCallbackInterface.java:130)

    >> evt = javaObjectEDT(nujira.EventTest) evt = nujira.EventTest@64902cf8 >> evt = handle(evt, 'CallbackProperties') evt = javahandle_withcallbacks.nujira.EventTest >> get(evt) Class: [1x1 java.lang.Class] TestEventCallback: [] TestEventCallbackData: [] >> set(evt,'TestEventCallback',@(h,e)disp(h)) java.lang.NullPointerException at com.mathworks.jmi.bean.MatlabBeanInterface.addCallback(MatlabBeanInterface.java:484) at com.mathworks.jmi.bean.MatlabCallbackInterface.addCallback(MatlabCallbackInterface.java:130)

    Any pointers?

    • Yair Altman September 12, 2014 at 08:22 Reply

      @Sean – as I explained here, you need to place the relevant class folder/JAR in Matlab’s static Java classpath.

      • Sean Lynch September 12, 2014 at 08:59

        Thank you, using the static path worked (but I had to use “javaclasspath.txt” in the prefdir() instead). The callback now sets, but the value looks wrong:

        >> set(evt,'TestEventCallback',@(h,e)disp(h))
        >> get(evt)
                            Class: [1x1 java.lang.Class]
                TestEventCallback: @(h,e)disp(h)
            TestEventCallbackData: []
         
        >> evt.notifyMyTest
        	javahandle_withcallbacks.nujira.EventTest

        >> set(evt,'TestEventCallback',@(h,e)disp(h)) >> get(evt) Class: [1x1 java.lang.Class] TestEventCallback: @(h,e)disp(h) TestEventCallbackData: [] >> evt.notifyMyTest javahandle_withcallbacks.nujira.EventTest

        Your example showed:

        >> set(evt,'TestEventCallback',@(h,e)disp(h))
        >> get(evt)
        	Class = [ (1 by 1) java.lang.Class array]
        	TestEventCallback = [ (1 by 1) function_handle array]
        	TestEventCallbackData = []
         
        >> evt.notifyMyTest   % invoke Java event
                      0.0009765625   % Matlab callback

        >> set(evt,'TestEventCallback',@(h,e)disp(h)) >> get(evt) Class = [ (1 by 1) java.lang.Class array] TestEventCallback = [ (1 by 1) function_handle array] TestEventCallbackData = [] >> evt.notifyMyTest % invoke Java event 0.0009765625 % Matlab callback

        We are nearly there.
        PS: I do have a copy of your book which has been very helpful.

      • Yair Altman September 13, 2014 at 09:40

        This is due to the difference between running platforms and/or Matlab releases. If you’d like my assistance in helping you on your specific platform, contact me offline for a consulting proposal.

  3. Danielle D January 3, 2015 at 14:59 Reply

    Running Matlab 2014b, I had the same problem the Sean Lynch posted:

    >> h_evt = handle(evt, 'CallbackProperties');
    >> set(h_evt,'TestEventCallback',@(h,e)disp(h))
    >> get(h_evt)
                        Class: [1x1 java.lang.Class]
            TestEventCallback: @(h,e)disp(h)
        TestEventCallbackData: []
     
    >> evt.notifyMyTest
    	javahandle_withcallbacks.EventTest

    >> h_evt = handle(evt, 'CallbackProperties'); >> set(h_evt,'TestEventCallback',@(h,e)disp(h)) >> get(h_evt) Class: [1x1 java.lang.Class] TestEventCallback: @(h,e)disp(h) TestEventCallbackData: [] >> evt.notifyMyTest javahandle_withcallbacks.EventTest

    But trying something like

    >> set(h_evt,'TestEventCallback',@(h,e)disp('test'))
    >> h_evt.notifyMyTest
    test

    >> set(h_evt,'TestEventCallback',@(h,e)disp('test')) >> h_evt.notifyMyTest test

    demonstrates that it is working. One step at a time.

    Thank you! This article helped a lot as well as the previous article: http://undocumentedmatlab.com/blog/matlab-callbacks-for-java-events/.

  4. Dave Brown August 24, 2015 at 10:49 Reply

    I ran into a problem from using java 7 that took a while to discover so I thought I’d share it. Hopefully it helps those with the same problem in the future.

    >> jScrollbar = javaObjectEDT('javax.swing.JScrollBar');
    >> hjScrollbar = handle(jScrollbar,'CallbackProperties');
    >> set(hjScrollbar, 'StateChangedCallback', callback);
    Error using javahandle_withcallbacks.javax.swing.JScrollBar/set
    The name 'StateChangedCallback' is not an accessible property for an instance of class 'javax.swing.JScrollBar'. 
     
    >> ver
    ...
    Java Version: Java 1.7.0_11-b21 with Oracle Corporation Java HotSpot(TM) 64-Bit Server VM mixed mode
    ...

    The problem is java 7 has changed the interface to the component and it is no longer a state change event but an adjustment event.
    (see http://www.java2s.com/Code/Java/Swing-JFC/ListeningforScrollbarValueChangesinaJScrollPaneContainer.htm). It is corrected by using hjScroll.AdjustmentValueChangedCallback in this example. Be on the lookout for these types of changes in the java interface.

  5. Matthew Harrison November 11, 2015 at 10:30 Reply

    Does anyone know how to get the window events like window closing using this method?

    • Yair Altman November 11, 2015 at 12:37 Reply
      jFigPeer = get(handle(gcf),'JavaFrame');
      jFrame = handle(jFigPeer.fHG2Client.getWindow, 'CallbackProperties');
      jFrame.WindowClosingCallback = @myCallback;

      jFigPeer = get(handle(gcf),'JavaFrame'); jFrame = handle(jFigPeer.fHG2Client.getWindow, 'CallbackProperties'); jFrame.WindowClosingCallback = @myCallback;

    • Matthew Harrison November 12, 2015 at 14:50 Reply

      Is there a clean way to do it from when your loading a .jar file?

      For example I have a .jar file called test.jar
      I call it like jFrame=test(); after adding it to the dynamic Java classpath
      but that jFrame doesnt have properties to getWindow or JavaFrame?

      • Yair Altman November 12, 2015 at 15:35

        JAR files contain Java classes, not Matlab figures. The entire blog here discusses Matlab.

  6. Muthukumar January 26, 2017 at 08:57 Reply

    How do I get delimiter of the date format ?

    example :
    system foramt – 1/23/2017
    Get Output from your script – mm dd,yyyy

    I need output like – dd/mm/yyyy

    Thanks in Advance

    • Yair Altman January 26, 2017 at 10:27 Reply

      You can either use the Java SimpleDateFormat class to convert the date format into your desired output format (read the Java docs online to see how to do this), or use Matlab’s datenum and datestr functions with the appropriate format specifiers (read the corresponding Matlab docs to see how to do this).

  7. Neeks January 2, 2020 at 21:11 Reply

    This looks elegant. Thank you. One issue I am not able to sort out – on maximizing the figure window the location of “javax.swing.JSlider” object does not scale properly?Is there a way to specify the ‘Units’,’normalize’ property like we do in uicontrol() to maintain the scaling and location.

    • Yair Altman January 3, 2020 at 02:16 Reply

      The javacomponent function returns 2 objects: a Java reference and a Matlab container. Simply set the value of the Units property of the Matlab container to ‘normalized’:

      [hjSlider, hContainer] = javacomponent(javax.swing.JSlider, pixelPosition, gcf);
      hContainer.Units = 'normalized';

      [hjSlider, hContainer] = javacomponent(javax.swing.JSlider, pixelPosition, gcf); hContainer.Units = 'normalized';

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