Pure Java Code to Call JavaFX Class

Posted: June 20th, 2009 under JavaFX, JavaFX Coding.
Tags: , ,


In my previous post Interoperability between JavaFX and Java, I discussed three possible approaches to invoke JavaFX features from the Java side. These approaches were:

1. The ScriptEngineManager class. It is based on JSR-223, the java scripting API, which allows a java program to call a script(such as JavaFX Script, javascript).
2. The JavaFX reflection API. It can probably call any classes in JavaFX.
3. The JavaFX class implements a Java interface so that a Java program can invoke the JavaFX class via the interface. The interface acts as a bridge between the two sides.

The third one seems the most elegant to call JavaFX from Java. However, there is a drawback: the program should start from the JavaFX side. The reason is that it is simpler to use JavaFX code to instantiate the JavaFX classes which can be passed to Java code. Nevertheless, in some scenario, it would be better to start the program from the java side. For example, if you want to add in some JavaFX features to an existing large java application, it is better to have java code as the entry point. To solve this issue, I am combining the essence of Approach 2 and 3 to create the below example.

Let’s say we want to invoke the latest charting functions of JavaFX 1.2 from the java code. We will first use the JavaFX reflection API to instantiate the JavaFX class. We then use it via its java interface. So we define a Java interface first.

/*
 * JavaInterface.java
 *
 * @author Henry Zhang      http://www.javafxgame.com
 */
package javatest;
public interface JavaInterface {
  public void addData(String name, float data);
  public void showChart();
}

The next step is to create a JavaFX class MyChart to implements this interface:

/*
 * MyChart.fx
 *
 * @author Henry Zhang     http://www.javafxgame.com
 */
package javatest;

import javafx.scene.chart.PieChart;
import javafx.scene.Scene;
import javafx.scene.text.Font;
import javafx.scene.text.Text;
import javafx.stage.Stage;
import javafx.scene.chart.PieChart3D;

public class MyChart extends JavaInterface {
  var chartData :  PieChart.Data[] = [];
  
  public override function addData( l:String, v: Number):Void {
    var labelString = l;

    var data =  PieChart.Data {
      label : l
      value : v
      action: function() {
        println("{labelString} clicked!");
      }
     } ;

    insert data into chartData;
  }

  public override function showChart() : Void {
    var chart =
      PieChart3D {
        data : chartData
        pieThickness: 25
        pieLabelFont: Font{ size: 9 };
        pieToLabelLineOneLength: 10
        pieToLabelLineTwoLength : 20
        pieLabelVisible: true
        pieValueVisible: true
        translateY: -50
     };

    Stage {
      title: "PieChart Window"
      width: 520
      height: 300
      scene: Scene {
        content: [
          Text {
            font : Font {
                    size : 16
                   }
            x: 200
            y: 20
            content: "Pie Chart"
          },
          chart
        ]
      }
    }
  }
}

The last thing is to write the java main class JavaTest.

/* 
 * JavaTest.java
 * @author Henry Zhang    http://www.javafxgame.com
 */
package javatest;

import javafx.reflect.FXClassType;
import javafx.reflect.FXLocal;
import javafx.reflect.FXLocal.Context;
import javafx.reflect.FXLocal.ObjectValue;

public class JavaTest {
  public static void main(String args[]) {
    Context context = FXLocal.getContext();
    FXClassType instance = context.findClass("javatest.MyChart");
    ObjectValue obj = (ObjectValue)instance.newInstance();

    JavaInterface ji = (JavaInterface)obj.asObject();

    String [] labels = {"January", "Febuary", "March", "April"};
    int [] values = { 18, 20, 25, 37 };

    for ( int i=0; i < values.length; i++ ) {
      ji.addData(labels[i], values[i]);
    }

    ji.showChart();
  }
}

In the above code, there are three lines for instantiating a JavaFX class via reflection:

    Context context = FXLocal.getContext();
    FXClassType instance = context.findClass("javatest.MyChart");
    ObjectValue obj = (ObjectValue)instance.newInstance();

The next line is to convert the JavaFX instance into a java interface so that it can be used by Java code:

    JavaInterface ji = (JavaInterface)obj.asObject();

If you are using NetBeans IDE, you can set javatest.JavaTest as the main class in your project properties(so that it can be the entry point of your program). Build this project you will get a javatest.jar. Running this program produces the below screenshot:


Java PieChart via JavaFX

To run it from the command line, use the below command:

   javafx -jar javatest.jar

Actually, you could do it in the purest java style by including all the JavaFX runtime stuffs, the command would look like this:

 java -Djava.library.path="<path to javafx sdk lib>" 
     -classpath "<all javafx sdk jars>" -jar javatest.jar

Since there are many jar files used by the JavaFX, this purest java approach turns out to be very troublesome. I would rather use the javafx command, which is a wrapper of the above java command.

Please leave comments if you have any questions.

This article is cross-posted at Calling JavaFX Classes from Pure Java Code. The Chinese translation can be found at http://www.javafxblogs.com.

JavaFX Used in Winter Olympic Games 2010
Review on Essential JavaFX
US Citizenship Practice Test

7 Comments

  • Comment by S├ębastien Stormacq — June 21, 2009 @ 3:34 am

    1

    Cool ! Thanks for sharing this !
    Any chance to include JavaFX in a Swing based application ?
    What about the posisbility to include a PieChart in a JPanel for example ?

    Seb

    Hi Seb,

    You can visit this post to see how to put JavaFX components into Java Swing application.

    Henry


  • Pingback by Interoperability between JavaFX and Java — June 21, 2009 @ 10:09 pm

    2

    […] [Update: Please refer to my latest article for discussion on Pure Java Code to Call JavaFX Class] […]


  • Comment by julien — July 10, 2009 @ 12:47 am

    3

    Great article ! I would like to use the javaFX java2d capabilities to create an image server : resize / format images with javaFx in a servlet. Do you know if it’s possible ?

    Hi Julien,

    Since JavaFX is not thread safe, i.e. multithreading in JavaFX may not work, it may not fit well in a web/servlet environment. You could use com.sun.javafx.runtime.Entry.deferAction() to run everything on your server code, but that would probably degrade performance. Anyway, you can give it a try and see how it works.

    Rgds,
    Henry


  • Comment by Raiden2010 — August 2, 2009 @ 10:51 pm

    4

    hi Julien!

    Great work Julien!But unfortunately I can’t run your app,please help me!.Can you explain me how to configure netbeans to run this project?.Is this a java project or javafx project.I already add all jar files to project library.But I can’t run the application in netbeans.Is it possible to run javafx file in java project?


  • Comment by Raiden2010 — August 2, 2009 @ 10:59 pm

    5

    Sorry Henry!I misunderstood your name!


  • Comment by Raiden2010 — August 2, 2009 @ 11:24 pm

    6

    Finally got some error!

    Exception in thread “main” java.lang.ClassCastException: MyChart cannot be cast to innovation_java.JavaInterface
    at innovation_java.JavaTest.main(JavaTest.java:20)
    Java Result: 1
    BUILD SUCCESSFUL (total time: 0 seconds)

    why?


    Hi Raiden2010,

    I think you should create a JavaFX project and then use my code. The starting(main) class of your project is your java class (JavaTest.java). This should get rid of the compilation error. Please refer to my article for more info to build project with JavaFX and Java:

    Calling JavaFX Classes from Pure Java Code.

    Rgds,
    Henry


  • Comment by Raiden2010 — August 5, 2009 @ 8:43 pm

    7

    Hi Henry!

    Finally it is worked!Thank you for your kind explanation sir!Thank you very mach!


RSS feed for comments on this post.