Friday, December 30, 2011

Integrating JavaFX 2.0 with Swing and SWT

One of the improvements in JavaFX with JavaFX 2.0 has been greater ease of interoperability with Swing and SWT. Several online resources document how this is done. These include Integrating JavaFX into Swing Applications and SWT Interop. However, in a nice example of effective class-level Javadoc documentation, the respective JavaFX classes javafx.embed.swing.JFXPanel and javafx.embed.swt.FXCanvas each provide a simple code sample of how to use the class to embed JavaFX into Swing or SWT code. In this post, I build upon the code samples provided in these classes' Javadoc documentation to demonstrate JavaFX integration with Swing and SWT.

Both JFXPanel and FXCanvas allow a JavaFX Scene to be set on their instance. The instance of Scene (based on my Simple JavaFX 2.0 Text Example post) to be be used in my examples in this post are provided by the method shown in the next JavaFX-specific code example.

Method Providing a JavaFX Scene for Integration
package dustin.examples;

import javafx.scene.Group;
import javafx.scene.Scene;
import javafx.scene.effect.*;
import javafx.scene.paint.Color;
import javafx.scene.text.Font;
import javafx.scene.text.FontWeight;
import javafx.scene.text.Text;

/**
 * Simple class intended to be used by two examples of integrating JavaFX with
 * Swing and with SWT. Provides single method {@code createScene()} to be used
 * by the classes that are examples of integrating Swing with JavaFX and SWT
 * with JavaFX.
 * 
 * @author Dustin
 */
public class TextIntegrationSceneCreator
{
   /**
    * Provides an instance of Scene with JavaFX text examples.
    * 
    * @return Instance of Scene with text examples.
    */
   public static Scene createTextScene()
   {
      final Group rootGroup = new Group();
      final Scene scene = new Scene(rootGroup, 800, 400, Color.BEIGE);

      final Text text1 = new Text(25, 25, "(2007) JavaFX based on F3");
      text1.setFill(Color.CHOCOLATE);
      text1.setFont(Font.font(java.awt.Font.SERIF, 25));
      rootGroup.getChildren().add(text1);

      final Text text2 = new Text(25, 50, "(2010) JavaFX Script Deprecated");
      text2.setFill(Color.DARKBLUE);
      text2.setFont(Font.font(java.awt.Font.SANS_SERIF, 30));
      rootGroup.getChildren().add(text2);

      final Text text3 = new Text(25, 75, "(2011) JavaFX to be Open Sourced!");
      text3.setFill(Color.TEAL);
      text3.setFont(Font.font(java.awt.Font.MONOSPACED, 35));
      rootGroup.getChildren().add(text3);

      final Text text4 = new Text(25, 125, "(2011) JavaFX to be Standardized");
      text4.setFill(Color.CRIMSON);
      text4.setFont(Font.font(java.awt.Font.DIALOG, 40));
      final Effect glow = new Glow(1.0);
      text4.setEffect(glow);
      rootGroup.getChildren().add(text4);

      final Text text5 = new Text(25, 175, "(Now) Time for JavaFX 2.0!");
      text5.setFill(Color.DARKVIOLET);
      text5.setFont(Font.font(java.awt.Font.SERIF, FontWeight.EXTRA_BOLD, 45));
      final Light.Distant light = new Light.Distant();
      light.setAzimuth(-135.0);
      final Lighting lighting = new Lighting();
      lighting.setLight(light);
      lighting.setSurfaceScale(9.0);
      text5.setEffect(lighting);
      rootGroup.getChildren().add(text5);

      final Text text6 = new Text(25, 225, "JavaFX News at JavaOne!");
      text6.setFill(Color.DARKGREEN);
      text6.setBlendMode(BlendMode.COLOR_BURN);
      text6.setFont(Font.font(java.awt.Font.DIALOG_INPUT, FontWeight.THIN, 45));
      final Reflection reflection = new Reflection();
      reflection.setFraction(1.0);
      text6.setEffect(reflection);
      rootGroup.getChildren().add(text6);

      return scene;      
   }
}

A JavaFX Scene can be integrated into Swing code via the JavaFX class JFXPanel and its setScene(Scene) method. This is demonstrated in the next code listing, which gets the particular Scene instance from the method in the previous code listing.

JavaFX/Swing Integration with JFXPanel
package dustin.examples;

import javafx.application.Platform;
import javafx.embed.swing.JFXPanel;
import javafx.scene.Scene;
import javax.swing.JFrame;
import javax.swing.SwingUtilities;

/**
 * Simple class demonstrating interoperability between Swing and JavaFX. This
 * class is adapted from the example provided in the Javadoc documentation for
 * {@code javafx.embed.swing.JFXPanel}.
 */
public class SwingJavaFxInteroperabilityDemo
{
   private static void initAndShowGUI()
   {
      // This method is invoked on Swing thread
      final JFrame frame = new JFrame("JavaFX / Swing Integrated");
      final JFXPanel fxPanel = new JFXPanel();
      frame.add(fxPanel);
      frame.setVisible(true);

      Platform.runLater(new Runnable()
      {
         @Override
         public void run()
         {
            initFX(fxPanel);
         }
      });
   }

   private static void initFX(JFXPanel fxPanel)
   {
      // This method is invoked on JavaFX thread
      final Scene scene = TextIntegrationSceneCreator.createTextScene();
      fxPanel.setScene(scene);
   }

   public static void main(String[] arguments)
   {
      SwingUtilities.invokeLater(new Runnable()
      {
         @Override
         public void run()
         {
            initAndShowGUI();
         }
      });
   }   
}

The output of running this simple Java Swing application with embedded JavaFX Scene is shown next.

Integrating SWT with JavaFX is arguably even easier and is demonstrated in the next code listing. As with the Swing integration example, the main approach is to call FXCanvas's setScene(Scene) method.

JavaFX/SWT Integration with FXCanvas
package dustin.examples;

import javafx.embed.swt.FXCanvas;
import javafx.scene.Scene;
import org.eclipse.swt.SWT;
import org.eclipse.swt.layout.FillLayout;
import org.eclipse.swt.widgets.Display;
import org.eclipse.swt.widgets.Shell;

/**
 * Simple class demonstrating interoperability between SWT and JavaFX. This
 * class is based on the example provided in the Javadoc documentation for
 * {@code javafx.embed.swt.FXCanvas}.
 * 
 * @author Dustin
 */
public class SwtJavaFxInteroperabilityDemo
{
   public static void main(String[] arguments)
   {
      final Display display = new Display();
      final Shell shell = new Shell(display);
      shell.setText("JavaFX / SWT Integration");
      shell.setLayout(new FillLayout());
      final FXCanvas canvas = new FXCanvas(shell, SWT.NONE);
      final Scene scene = TextIntegrationSceneCreator.createTextScene();
      canvas.setScene(scene);
      shell.open();
      while (!shell.isDisposed())
      {
         if (!display.readAndDispatch()) display.sleep();
      }
      display.dispose();
   }   
}

The next screen snapshot shows what this simple SWT application with embedded JavaFX looks like.

The code listings for Swing integration with JavaFX and for SWT integration with JavaFX shown above are only slightly adapted from the Javadoc documentation for the JavaFX classes JFXPanel (Swing) and FXCanvas (SWT). It is nice that these classes provide these examples in their documentation and it is really nice that integration has become so much easier. For more thorough coverage of JavaFX/Swing integration, see Integrating JavaFX into Swing Applications.

4 comments:

Tadashi Ohmura said...

Thank you for your very good sample code.

The code helps me to make a modal dialog in JavaFX application.

I thought that I can not make a modal dialog in JavaFX
becuase Stage.show() returns immediately.

If we set JavaFX Scene object onto JFXPanel within JDialog
so we use this JDialog as a modal dialog in JavaFX application.

Thanks

@DustinMarx said...

Tadashi,

Thanks for the feedback and thanks for providing your idea regarding use of JDialog. That's a nice extension example of integrating JavaFX and Swing.

Dustin

ARI said...

Muy bueno y muy didáctico. Gracias Dustin.

@DustinMarx said...

Additional posts on integrating Swing and JavaFX are Dirk Lemmermann's JavaFX Tip 9: Do Not Mix Swing / JavaFX and Pedro Duque Vieira's posts Integrating JavaFX and Swing and Integrating JavaFX and Swing (Revised).