Sunday Jul 05, 2009

How to use JavaFX in your Swing Application - JavaFX 1.2 version.

At one of my sessions showing off JavaFX, I was asked the question, how can I run JavaFX in my Swing Application? At first, I asked why do you want to do this? The answer was we have built up the Swing application over many years and cannot rewrite it all at once, but we would like to take advantage of  JavaFX's features. This sounded reasonable to me.

So I did some investigation and found that there is a blog about this at http://blogs.sun.com/javafx/entry/how_to_use_javafx_in. However, this only covered JavaFX 1.1. Now, that JavaFX 1.2 is out, this is no longer applicable. Here is how to do it in JavaFX 1.2.

We start with the obligatory warning, this is only for the Desktop profile, and do not try this at home unless you are a highly trained professional. This, like the previous way to do this, is a hack. It uses private APIs in JavaFX and is subject to change with any new release.

First, we need to pull the underlying Swing Component out from the Scene class. To do this, we need to use JavaFX reflection from a Java class. This is done by passing in the name of the Scene class, creating an object for it via reflection, then locating its underlying Swing implementation, and finally pulling out the Scenegraph JSGPanel, that is a Swing Component. The following listing shows how to do this.


package scene;

import com.sun.javafx.tk.swing.SwingScene;
import com.sun.scenario.scenegraph.JSGPanel;
import javafx.reflect.\*;
import javafx.reflect.FXLocal.ObjectValue;

public class LoadScene {
    private static FXLocal.Context context = FXLocal.getContext();

    public static JSGPanel loadScene(String classname) {
        FXClassType classRef = context.findClass(classname);
        FXLocal.ObjectValue obj = (ObjectValue) classRef.newInstance();
        FXFunctionMember getPeer = classRef.getFunction("impl_getPeer");
        FXLocal.ObjectValue peer = (ObjectValue) getPeer.invoke(obj);
        SwingScene scene = (SwingScene)peer.asObject();

        return scene.scenePanel;
    }
}

Next, to use this in a Swing application, we create the Swing Components normally, leaving a JPanel that will hold the JSGPanel that represents the JavaFX scene. An example using a JavaFX scene, "scene.MyScene", that runs a simple animation is:


public class TheFrame extends javax.swing.JFrame {

    /\*\* Creates new form TheFrame \*/
    public TheFrame() {
        initComponents();⁞
        jPanel1.add(LoadScene.loadScene("scene.MyScene"), BorderLayout.CENTER);
    }⁞
                       
    private void initComponents() {

        jPanel1 = new javax.swing.JPanel();

        setDefaultCloseOperation(javax.swing.WindowConstants.EXIT_ON_CLOSE);
        setTitle("JFrame - JavaFX Panel Test");
        getContentPane().setLayout(new java.awt.FlowLayout());

        jPanel1.setLayout(new java.awt.BorderLayout());
        getContentPane().add(jPanel1);

        pack();
    }                

    public static void main(String args[]) {
        java.awt.EventQueue.invokeLater(new Runnable() {
            public void run() {
                new TheFrame().setVisible(true);
            }
        });
    }                   
    private javax.swing.JPanel jPanel1;                  
}

To complete the exercise, we need to add the JavaFX jar files (including javafxc.jar) to the classpath, then use "java" to start the application.

Here is the picture of the JavaFX scene running within the Swing JFrame. This simple JavaFX application shows an animation of "Hello World" moving across the scene.

Swing hosting JavaFX scene

I have contributed an implementation based on this class to the JFXtras project at http://code.google.com/p/jfxtras/. It is now included in JFXtras release 0.5 and the class to use is org.jfxtras.scene.SceneToJComponent.

About

jimclarke

Search

Categories
Archives
« April 2014
SunMonTueWedThuFriSat
  
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
   
       
Today