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.

Comments:

Hi,
Is there a definite way to dispose JavaFX scene object and gc it ?
It seems that the JavaFX is not properly gc when it is removed from the frame and still consuming memory. Due to sophisticated binding and advanced features of JavaFX, memory leak and consumption are major concern when trying to creating practical "enterprise" application which require restarting periodically for stability reason. Hopefully the next JavaFX version can address that.

I still think that it will take a very long time before JavaFX reaches the maturity and richness of Swing's API and library.

Posted by GeekyCoder on July 05, 2009 at 03:21 PM EDT #

Cool ! Thank !

Posted by Sebastien Stormacq on July 05, 2009 at 09:18 PM EDT #

With JXScene you could get the scriptObject and cast it to an interface, this way you could call methods of the scene from the java side.

Without an option to get the scene object, there is no communication between java and javafx making this rather useless.

Posted by Pedro Duque Vieira on July 10, 2009 at 11:53 AM EDT #

All this still continues to send totally mixed messages from Sun. Sun's OWN LICENSE prohibits redistributing and JavaFX component, so all this Swing/FX integration is applicable only to WebStart apps.

Posted by Alex on July 15, 2009 at 03:02 AM EDT #

Great work James!But can you explain me about how can I run this project in netbeans ? That is too complicated to me!

Thanks!

Posted by Raiden2010 on August 03, 2009 at 12:44 AM EDT #

This suck that we have to use a Hack ... when will an official way of communication between swing and javaFx be available ?

Posted by Ar3s on August 26, 2009 at 08:18 PM EDT #

Hello,

can someone help me?
I can't import the packe below.
My NetBean IDE can't find them
The error message is: package does not exist.

all these packages doest not exits:
com.sun.javafx.tk.swing.SwingScene;
com.sun.scenario.scenegraph.JSGPanel;
javafx.reflect.\*;
javafx.reflect.FXLocal.ObjectValue;

Where can i get them?

Posted by guest on September 25, 2009 at 12:59 AM EDT #

Ok, I was able to successfully get the scene to show in a JPanel.

However I noticed that the scene doesn't resize when I resize the JPanel. My question is this. How do you get the scene to resize with the JPanel? Normally you set the resizable attribute to true and resize the rectangle that it the first item in the content attribute of the scene. So how do I do the same thing when I am declaring the scene as a class?

Posted by SteveR on April 14, 2010 at 09:31 AM EDT #

Post a Comment:
  • HTML Syntax: NOT allowed
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