Those of you familiar with Swing may have noticed an error in the last post. This is a correction to First Steps “Hello OnJava”.

On the JavaFX users mailing list Dean Iverson pointed out that the intermittent exceptions at startup where most likely due to the fact that I wasn’t using SwingUtilities.invokeLater(). Here’s the text of his reply:

When I see intermittent exceptions at startup, the first thing I think of is manipulating components off of the EDT. I see from your code that you are creating your frame, running your script, and setting the frame visible from the app’s main thread. The first thing I would try is to wrap that stuff in a Runnable and use SwingUtils.invokeLater.

Right, right, it’s been so long since I’ve picked up Swing I forgot about this. But, this makes perfect sense, part of the promise of JavaFX is that it is going to convince programmers like myself to reconsider Java GUI programming. Hopefully following the series will help others in the same situation.

Read more to see the modified Main.java from the previous post…

Fixing the Error: Main.java

Based on his feedback, I refreshed my Swing memory and put all of the script execution code into a Runnable which is invoked by SwingUtilities.invokeLater(). Here’s the new class:

package com.oreilly.onjava.feedticker;

import java.io.IOException;
import java.net.MalformedURLException;
import java.net.URL;
import java.util.Arrays;
import java.util.Date;
import javax.script.Bindings;
import javax.script.ScriptContext;
import javax.script.ScriptEngine;
import javax.script.ScriptEngineManager;
import javax.script.ScriptException;
import javax.script.SimpleScriptContext;
import javax.swing.JFrame;
import javax.swing.SwingUtilities;

public class Main {
    
    public Main() {
    }
    
    public static void main(String[] args) throws Exception {
        
        final FeedReader reader = new FeedReader(new URL("http://www.oreillynet.com/onjava/blog/atom.xml"));
        reader.read();
        
        final JFrame frame = new JFrame("Ticker");
        frame.setDefaultCloseOperation( JFrame.EXIT_ON_CLOSE );
        frame.setSize( 500, 400 );
        
        Runnable executeScript = new Runnable() {
            
            public void run() {
                ClassLoader loader =
                        Thread.currentThread().getContextClassLoader();
                ScriptEngineManager manager = new ScriptEngineManager(loader);
                ScriptEngine engine = manager.getEngineByExtension("fx");
                
                Bindings bindings = engine.createBindings();
                bindings.put("READER:com.oreilly.onjava.feedticker.FeedReader", reader);
                bindings.put("MY_CONTAINER:javax.swing.JComponent", frame.getContentPane());
                
                ScriptContext context = new SimpleScriptContext();
                // Bug workaround
                context.setBindings(bindings, ScriptContext.GLOBAL_SCOPE);
                context.setBindings(bindings, ScriptContext.ENGINE_SCOPE);
                
                engine.setContext(context);
                String script =
                        "import com.oreilly.onjava.feedticker.Ticker;";
                try {
                    engine.eval(script);
                } catch( ScriptException se ) {
                    System.out.println( "Blah" );
                }
                
                frame.setVisible(true);
            }
            
        };
        
        SwingUtilities.invokeLater( executeScript );
    }
    
}

it Works

Works like a charm…..now I have to go update the previous post with a pointer to this one…