Deprecated: Assigning the return value of new by reference is deprecated in /home/citiz68/public_html/javafxgame/wp-settings.php on line 472

Deprecated: Assigning the return value of new by reference is deprecated in /home/citiz68/public_html/javafxgame/wp-settings.php on line 487

Deprecated: Assigning the return value of new by reference is deprecated in /home/citiz68/public_html/javafxgame/wp-settings.php on line 494

Deprecated: Assigning the return value of new by reference is deprecated in /home/citiz68/public_html/javafxgame/wp-settings.php on line 530

Deprecated: Assigning the return value of new by reference is deprecated in /home/citiz68/public_html/javafxgame/wp-includes/cache.php on line 103

Deprecated: Assigning the return value of new by reference is deprecated in /home/citiz68/public_html/javafxgame/wp-includes/query.php on line 21

Deprecated: Assigning the return value of new by reference is deprecated in /home/citiz68/public_html/javafxgame/wp-includes/theme.php on line 623
JavaFX Scene Embedded in a Swing Window

JavaFX Scene Embedded in a Swing Window

Posted: July 8th, 2009 under JavaFX Technology.
Tags: , , ,

Bookmark and Share

In Stephen Chin’s open source project JFXtras, a JavaFX wrapper for Swing is included in the current release(V0.5). This wrapper allows us to put JavaFX GUI components into a SWING application. It is very useful for developers to integrate JavaFX GUI features with their Java Swing applications.


The JFXtras project comes with a sample test program( refer to SceneToJComponentScene.fx and SceneToJComponentTest.java). I suppose that Swing developers are probably interested in this topic, so I modified the code a bit and created the below example for better illustration purposes.


First we create a subclass of the Scene. Since the Scene class is the top level container in JavaFX , we can virtually place any GUI components in it and then make a reference to it from the java side. Let’s look at the code:

/*
 * MyScene.fx     http://www.javafxgame.com
 * @author Henry Zhang
 */

package swingtest;

import javafx.scene.Scene;
import javafx.scene.text.*;
import javafx.scene.paint.*;
import javafx.scene.shape.Rectangle;
import javafx.animation.Timeline;
import javafx.animation.KeyFrame;

def w = 500;
def h = 400;

public class MyScene extends Scene {
    var xx = w / 3;
    var yy = h / 2;
    var rotate = 0;
    var text = "";

    var tl = Timeline {

      repeatCount: Timeline.INDEFINITE
      keyFrames : [
        KeyFrame {
          time: 70ms
          action: function() {
             text = JavaFXToSwingTest.tf.getText();
             rotate = (rotate+5) mod 360;
          }
        }
      ]
     }

     override var content= [
        Rectangle {
            width: w, height: h
            fill: Color.BLUE
        },
        Text {
            font : Font {
                    size: 24
                   }
            layoutX: bind  xx
            layoutY: bind yy
            rotate: bind rotate
            content: bind text
            fill: Color.YELLOW
        }
    ];

    init { tl.play(); }
}


In the above MyScene.fx, we define a Timeline object to play an animation of a Text instance. Every 70ms, the text will be rotated by an angle of 5 degree. To demostrate the data exchange between JavaFX and java, we update the content of the text for each cycle of the animation. The line shown below is used to get data from a Java static variable:

text = JavaFXToSwingTest.tf.getText();


Though this is not an elegant approach to update data, we use it here for its simplicity. We will discuss more about this issue later. Now that we have a Scene class, we can work on the java class. The code of JavaFXToSwingTest.java is listed below:


package swingtest;

/**
 * JavaFXToSwingTest.java     http://www.javafxgame.com
 * @author Henry Zhang
 */
import java.awt.*;
import javax.swing.*;
import org.jfxtras.scene.SceneToJComponent;

public class JavaFXToSwingTest extends JFrame {

  public static JTextField tf = new JTextField("JavaFX for SWING");

  public JavaFXToSwingTest() {
    setDefaultCloseOperation(javax.swing.WindowConstants.EXIT_ON_CLOSE);
    setTitle("JavaFX in SWING Test");

    Container container = getContentPane();
    container.setLayout(new BorderLayout());

    String sceneClass = "swingtest.MyScene";
    JComponent myScene = SceneToJComponent.loadScene(sceneClass);

    JLabel label = new JLabel(" Below is a JavaFX Animation: ");
    container.add(label, BorderLayout.NORTH);
    container.add(myScene, BorderLayout.CENTER);

    JPanel p = new JPanel();
    p.setLayout(new FlowLayout());

    tf.setColumns(28);
    p.add(tf);
    p.add(new JButton("SWING Button"));

    container.add(p, BorderLayout.SOUTH);
    pack();
  }

  public static void main(String args[]) {
    java.awt.EventQueue.invokeLater(
      new Runnable() {
        public void run() {
          new JavaFXToSwingTest().setVisible(true);
        }
      });
  }
}


The code should be quite straightforward for most Java(Swing) programmers. We used BorderLayout and FlowLayout to arrange a few Swing widgets inside a JFrame. There are two lines to create the JavaFX scene to be loaded into a JFrame:

    String sceneClass = "swingtest.MyScene";
    JComponent myScene = SceneToJComponent.loadScene(sceneClass);


The SceneToJComponent class comes from the JFXtras project. Its loadScene() method loads a JavaFX Scene class and returns a JComponent object, which can be used as a normal Swing JComponent. Running the program you will see a text “JavaFX for SWING” rotating in a window(JFrame). If you change the sentence in the input box, you will see the rotating text changes as well. If you have Windows media player installed on your machine, you can click on the below screenshot to watch a video on how the program runs.


DISCUSSION

1) In the above program, we use the JavaFX code actively poll the data from a Java variable. This may waste quite some processing cycles. We can let the Java code notify JavaFX object instead. This requires a technique of invoking JavaFX classes from Java code. Interested readers can refer to this article for details: Java Code to Call JavaFX Classes.


2) Some people may ask how we should compile and run the code. There are basically two approaches for compiling the code. The first is to use javafxc to compile both the Java and JavaFX code. The second is to use javafxc to compile the JavaFX code into a jar file and javac for the java code. To run the program, you can choose either the javafx or java command. You can refer to my article Calling JavaFX Classes from Java Code for more explanations.


3) The last thing I need to point out is that the JFXtras project uses some internal APIs of JavaFX to implement the loadScene() method. This implies that the code may break in future releases of JavaFX. However, as pointed out by Steve, using the JFXtras Swing wrapper could insulate you from the changes of JavaFX APIs (i.e. he will take care of the changes for you). I think Steve is the one we can bank on, because he always acts fast to keep up with the latest JavaFX version. :)


Please leave comments if you have any questions.


Bookmark and Share

4 Comments

  1. [...] a Swing application, your best bet right now is to use the JFXtras library. Henry Zhang has a post showing you how to achieve this. Note that the way that this is achieved is not guaranteed to always work, and so take caution if [...]

    Pingback by Java desktop links of the week, July 6 | Jonathan Giles — July 16, 2009 @ 4:16 pm

  2. Awesome!!!

    I would like Feed RSS from this blog, but i cant found…

    Hi William,

    the feed of this blog is http://www.javafxgame.com/feed/

    Rgds,

    Henry

    Comment by William — July 24, 2009 @ 10:14 am

  3. [...] How to Display JavaFX Scene in a Swing Window Using JavaFX Features in Java Interoperability between JavaFX & Java How to Show a SWING Menu in JavaFX Convert Swing to JavaFX [...]

    Pingback by JavaFX API for Java? — July 29, 2009 @ 3:31 am

  4. good

    Comment by bhangun — August 2, 2009 @ 7:49 pm

RSS feed for comments on this post.