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!
- JavaFX and SWT share the same event loop when we embedding JavaFX into SWT using FXCanvas
- 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!
Pingback: JavaFX links of the week, February 17 // JavaFX News, Demos and Insight // FX Experience
Pingback: Java desktop links of the week, February 17 « Jonathan Giles
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();
}
}