Path: news.mathworks.com!not-for-mail
From: "Arwel Hughes" <a.v.hughes@rl.ac.uk>
Newsgroups: comp.soft-sys.matlab
Subject: Re: Profiling Java in Matlab
Date: Fri, 16 Nov 2007 12:05:25 +0000 (UTC)
Organization: STFC Rutherford Appleton Laboratory
Lines: 291
Message-ID: <fhk125$8rq$1@fred.mathworks.com>
References: <fcqhf3$fcj$1@fred.mathworks.com> <feg3vs$6ha$1@fred.mathworks.com> <fgaj1g$imo$1@fred.mathworks.com>
Reply-To: "Arwel Hughes" <a.v.hughes@rl.ac.uk>
NNTP-Posting-Host: webapp-02-blr.mathworks.com
Content-Type: text/plain; charset="ISO-8859-1"
Content-Transfer-Encoding: 8bit
X-Trace: fred.mathworks.com 1195214725 9082 172.30.248.37 (16 Nov 2007 12:05:25 GMT)
X-Complaints-To: news@mathworks.com
NNTP-Posting-Date: Fri, 16 Nov 2007 12:05:25 +0000 (UTC)
X-Newsreader: MATLAB Central Newsreader 408081
Xref: news.mathworks.com comp.soft-sys.matlab:437906



"Michael Bushe" <michael.bushe-removeme@mathworks.com> 
wrote in message <fgaj1g$imo$1@fred.mathworks.com>...
> "Wolfgang Ulmer" <spam@wulmer.de> wrote in message
> <feg3vs$6ha$1@fred.mathworks.com>...
> > Hi Michael,
> > 
> > while using Swing with Java, I discovered the same 
problem
> > which is due to the fact, that Matlab uses the AWT/Swing
> > Event  Handling Thread to do some computation.
> > 
> > You can even easily create a deadlock if you enter the
> > following commands on the prompt:
> > >> import com.mathworks.jmi.*;
> > >> matlab = Matlab;
> > >> matlab.eval('1+1'); 
> > 
> > I think, that one solution is not to use the java event
> > mechanisms but the Matlab methods for defining callback
> > routines.
> > 
> > Example:
> > 
> > button = JButton('Close');
> > set
(button,'ActionPerformedCallback',@buttonClosePressed);
> > 
> > function buttonClosePressed(handle,event)
> >    doSomething();
> > end
> > 
> > -------------
> > 
> > See http://xtargets.com/snippets/tag/java for details 
and
> > further examples.
> > 
> > Don't expect Mathworks to answer your question... they 
do
> > not support Java GUI-Matlab interaction.
> > 
> > Wolfgang
> 
> 
> Wolfgang's example will do most of what you want, and he 
is
> right - you need to use MATLAB-provided APIs for accessing
> Swing Events.  It is not correct, however, that MATLAB 
does
> computation on the AWT/Swing thread, this would lock up
> GUIs.  Also, using jmi classes is not a good idea.  They 
are
> not public or supported and it's easy to use them 
improperly
> (even for developers inside the MathWorks).  Lastly, there
> is a memory leak in the example, the workaround is 
detailed
> below, but first, let's discuss Swing threading.
> 
> The Swing threading problem is not specific to MATLAB.  In
> pure Java if you write the following innocent looking 
code,
> it is erroneous:
> 
> package example;
> 
> import javax.swing.*;
> 
> public class SwingApp {
>     JFrame frame = new JFrame();
>     JButton button = new JButton("Do Something");
> 
>     public void showFrame() {
>       frame.getContentPane().add(getButton());
>       frame.setDefaultCloseOperation
(JFrame.DISPOSE_ON_CLOSE);
>         frame.pack();
>         frame.setVisible(true);
>     }
> 
>     public JButton getButton() {
>         return button;
>     }
> 
>     public static void main(String args[]) {
>         //Wrong! Swing object construction not on the
> EventDispatchThread
>         SwingApp app = new SwingApp();
>         //Wrong! Swing component access not on the
> EventDispatchThread
>         app.showFrame();
>     }
> }
> 
> The problem is that the class is making Swing calls on
> Java's main thread.  Sun asks developers to follow the 
rule
> that all access to Swing components must occur on Swing's
> EventDispatchThread (there may be some leeway, but it's 
best
> to always follow the rule).  This may look like it works
> fine, but every so often you'll encounter lock ups and
> strange behavior like listeners not firing.
> 
> This rule is broken when calling Swing components from the
> MATLAB command line in the same manner since Swing calls 
are
> being made from the MATLAB thread:
> 
> >> javaaddpath c:\myapp\classes
> >> app = example.SwingApp;  % Wrong! Swing object
> construction not on the EventDispatchThread
> >> app.showFrame(); % Wrong! Swing component access not on
> the EventDispatchThread
> 
> In pure Java, the right way to write this code is to wrap
> all Swing calls in a Runnable that is later called on the
> EventDispatchThread:
> 
>     public static void main(String args[]) {
>         SwingUtilities.invokeLater(new Runnable() {
>             public void run() {
>                 SwingApp app = new SwingApp();
>                 app.showFrame();
>             }
>         });
>     }
> 
> How can you do the same from MATLAB?  There are additional
> undocumented APIs that you can use to avoid Java Swing
> threading issues, specifically awtcreate, awtinvoke and
> javacomponent.  These APIs are not yet final and are
> therefore undocumented and can change in future releases. 
> Please don&#8217;t expect this to be the best way to work with
> Swing Components going forward as we are planning to 
change
> these APIs.  We appreciate any feedback you can give us to
> help us deliver APIs that meet your needs.  
> 
> The functions awtcreate and awtinvoke both ship 
undocumented
> &#8211; open the M-file for example usage.  They both ensure 
that
> the work for the M command that interacts with the Java
> component happens on Java's EventDispathThread and not
> MATLAB's main thread.  
> 
> For the SwingApp, you can ensure the calls are pushed onto
> the EventDispatchThread by using awtcreate and awtinvoke
> like so:
> 
> >> app = awtcreate('example.SwingApp');
> >> awtinvoke(app, 'showFrame');
> 
> The undocumented awtcreate and awtinvoke commands are like
> wrapping each M line in a SwingUtiities.invokeLater call. 
> Though unsupported now, it works well.  
> 
> If you are writing your own Java classes, you may want to
> consider not using awtcreate and awtinvoke and push
> Swing-related Java code to your own classes.  This will 
make
> for better performance since it is one push to Swing's
> EventDispatchThread, not many.  
> 
> For example, you could run the example SwingApp above with
> the main() corrected to use SwingUtilities.invokeLater,
> directly from M:
> 
> >> example.SwingApp.main('')
> 
> Since the class's main() method calls invokeLater, this is
> safe.  
> 
> Rewriting your original example using awtcreate and
> awtinvoke would look like this:
> 
> button = awtcreate('javax.swing.JButton');
> awtinvoke(button,'setLabel','Close');
> 
> % make the button a handle object before calling set
> button = handle(button,'callbackproperties');
> set(button,'ActionPerformedCallback',@buttonClosePressed);
> javacomponent(button)
> 
> In addition to the awtcreate and awtinvoke usage, there 
are
> two other things to notice about the rewritten example:
> 1) It's better to use the "handle" command before calling
> "set" (this will prevent a memory leak).
> 2) The javacomponent command, also undocumented, puts any
> Java Swing component in a figure window &#8211; open the M-file
> for example usage.
> 
> This is tricky stuff especially since the threading issues
> are not immediately apparent.  We are interested in
> providing the best Java GUI experience we can in MATLAB. 
> Any feedback is greatly appreciated.
> 
> 



Michael,
I tried playing around with the example, and couldn't get 
it to work by calling the 'main' method as you suggest. It 
runs, but the callback doesn't seem to respond.

So, if I have the 'public static void main..' in there, and 
do this...

app = swingApp();
app.main('');
button = app.getButton();
buttonProps = handle(button,'callbackproperties');
set(buttonProps,'ActionPerformedCallback',@buttonPressed);

... the @buttonPressed callback doesn't get called on a 
button press.

However, if I comment out the 'public static...main' 
method, and call ShowFrame directly from Matlab like 
this....

app = swingApp()
app.ShowFrame();
button = app.getButton();
buttonProps = handle(button,'callbackproperties');
set(buttonProps,'ActionPerformedCallback',@buttonPressed);

.. it works fine. Am I doing something wrong?  The complete 
codes of the example I'm trying are below, matlab first 
(and yes, I know theres none of the threading bits in there 
yet.)

-mTest.m

function mTest()
clear
javaaddpath c:\java\matlabthreads2\Main\build\classes

app = swingApp();
%app.main('');
app.ShowFrame();

button = app.getButton();
buttonProps = handle(button,'callbackproperties');
set(buttonProps,'ActionPerformedCallback',@buttonPressed);

disp('debug')



function buttonPressed(src,ev)
disp('Button Pressed Callback');





- swingApp.java

import javax.swing.*;
import java.awt.*;

public class swingApp {
        JFrame frame = new JFrame();
        JButton button1 = new JButton("Do Something");
        
    public void ShowFrame() {
        frame.getContentPane().add(getButton());
        frame.setDefaultCloseOperation
(JFrame.DISPOSE_ON_CLOSE);
        frame.pack();
        frame.setSize(400,400);
        frame.setVisible(true);
    }
    
    
    public JButton getButton() {
        return button1;
    }
    
 /*   public static void main(String[] args) {
        swingApp app = new swingApp();
        app.ShowFrame();
}*/
}