Embedding Swing into SWT on Java8


If have have you ever faced the problem to embed Swing into your SWT application you know how nasty things get because you always have to synchronize between the SWT & Swing event loop.

So if you have code like:

Display d = ...;
Shell s = ...;
JButton swingButton = new JButton("Swing");
Button swtButton = new Button("SWT");
swingButton.addActionListener( (e) -> 
   d.asyncExec( 
    () -> swtButton.setEnabled(!swtButton.getEnabled()) 
   ) 
);
swtButton.addListener( SWT.Selection, (e) -> 
 SwingUtilities.invokeLater( 
    () -> swingButton.setEnabled(!swingButton.isEnabled()) 
   )
);

// .....

while(!s.isDisposed()) {
  if(!d.readAndDispatch()) {
    d.sleep();
  }
}

You might not be suprised that this all can lead to fairly complex and unmaintainable code!

Now let’s see what we can do with our JavaFX8 knowledge to make SWT and Swing share the same event loop!

  1. JavaFX and SWT share the same event loop when we embedding JavaFX into SWT using FXCanvas
  2. in Java8 Swing can be forced to run on the same event loop as JavaFX

If we carefully study the above this means:

JavaFX-Event-Loop == SWT-Event-Loop
Swing-Event-Loop  == JavaFX-Event-Loop
----------------------------------------
Swing-Event-Loop == SWT-Event-Loop

Hm – that’s interesting but how does this look like in code:

Display d = ...;
Shell s = ...;
// Make JavaFX run in embedded mode!
Shell dummy = new Shell(d);
FXCanvas c = new FXCanvas(dummy, SWT.NONE);
dummy.dispose();

JButton swingButton = new JButton("Swing");
Button swtButton = new Button("SWT");
swingButton.addActionListener( 
  (e) -> swtButton.setEnabled(!swtButton.getEnabled())
);
swtButton.addListener(SWT.Selection, 
  (e) -> swingButton.setEnabled(!swingButton.isEnabled())
);

// ...
while (!s.isDisposed()) {
  if (!d.readAndDispatch()) {
    d.sleep();
  }
}

d.dispose();
// Exit JavaFX-Platform
PlatformImpl.exit();

That’s all from a source code point of view to get things working – the only extra thing you need to to as well is to launch your SWT-Application with “-Djavafx.embed.singleThread=true”.

I’ve recorded a short screencast on this to show you some SWT/Swing code in action!

I’ve not extensively tested this code and I don’t think it is officially supported by Oracle but the above sample runs fine on Win32 and MacOSX 10.9 – so it is hack but I wanted to get out this information – use it at your own risk!

This entry was posted in e(fx)clipse. Bookmark the permalink.

3 Responses to Embedding Swing into SWT on Java8

  1. Pingback: JavaFX links of the week, February 17 // JavaFX News, Demos and Insight // FX Experience

  2. Pingback: Java desktop links of the week, February 17 « Jonathan Giles

  3. Acardiac says:

    You can do it without JavaFx:

    AWTAccessor.getEventQueueAccessor().setFwDispatcher(getEventQueue(),
    new SWTDispatcher());

    private static EventQueue getEventQueue() {
    return AccessController
    .doPrivileged(new PrivilegedAction() {
    @Override
    public EventQueue run() {
    return java.awt.Toolkit.getDefaultToolkit()
    .getSystemEventQueue();
    }
    });
    }

    public class SWTDispatcher implements FwDispatcher {

    @Override
    public SecondaryLoop createSecondaryLoop() {
    return null;
    }

    @Override
    public boolean isDispatchThread() {
    return getDisplay().getThread() == Thread.currentThread();
    }

    @Override
    public void scheduleDispatch(Runnable runnable) {
    getDisplay().asyncExec(runnable);
    }

    private static Display getDisplay()
    {
    final Display display = Display.getCurrent();
    return (display != null) ? display : Display.getDefault();
    }
    }

Leave a comment

This site uses Akismet to reduce spam. Learn how your comment data is processed.