Jython + JavaFX: Comienzo duro

Al fin Oracle liberó su versión final de JavFX en JavaOne 2011; También hay una versión beta para OSX la cual me baje de una vez.

Jugando con los ejemplos me dediqué a experimentar con el ejemplo de un gráfico de torta el cual se ve sencillo:

import javafx.application.Application;
import javafx.collections.FXCollections;
import javafx.collections.ObservableList;
import javafx.scene.Scene;
import javafx.stage.Stage;
import javafx.scene.chart.PieChart;
import javafx.scene.Group;

public class PieChartSample extends Application {

    @Override public void start(Stage stage) {
        Scene scene = new Scene(new Group());
        stage.setTitle("Imported Fruits");
        stage.setWidth(500);
        stage.setHeight(500);

        ObservableList pieChartData =
                FXCollections.observableArrayList(
                new PieChart.Data("Grapefruit", 13),
                new PieChart.Data("Oranges", 25),
                new PieChart.Data("Plums", 10),
                new PieChart.Data("Pears", 22),
                new PieChart.Data("Apples", 30));
        final PieChart chart = new PieChart(pieChartData);
        chart.setTitle("Imported Fruits");

        ((Group) scene.getRoot()).getChildren().add(chart);
        stage.setScene(scene);
        stage.show();
    }

    public static void main(String[] args) {
        launch(args);
    }
}

Lo compilamos y corremos:

Macintosh:javafx josevnz$ export CLASSPATH=/Users/Shared/javafx-sdk2.0.2-beta//rt/lib/jfxrt.jar:.
Macintosh:javafx josevnz$ javac PieChartSample.java -d .
Macintosh:javafx josevnz$ java PieChartSample

JavaFX Pie chartJavaFX gráfico de torta en acción

Así que traté de convertir este sencillo código a Jython:

#!/usr/bin/env jython
import sys
from javafx.application import Application
from javafx.collections import FXCollections
from javafx.collections import ObservableList
from javafx.scene import Scene
from javafx.stage import Stage
from javafx.scene.chart import PieChart
from javafx.scene import Group

class PieChartSample(Application):

    def __init__(self):
        pass

    def start(self, stage):
        scene = Scene(Group())
        stage.setTitle("Imported Fruits")
        stage.setWidth(500)
        stage.setHeight(500)

        pieChartData = FXCollections.observableArrayList(
                PieChart.Data("Grapefruit", 13),
                PieChart.Data("Oranges", 25),
                PieChart.Data("Plums", 10),
                PieChart.Data("Pears", 22),
                PieChart.Data("Apples", 30))
        chart = PieChart(pieChartData)
        chart.setTitle("Imported Fruits")

        scene.getRoot().getChildren().add(chart)
        stage.setScene(scene)
        stage.show()

if __name__ == "__main__":
        PieChartSample().launch(sys.argv[1:])

Pero al correrlo me se queja que no estoy extendiendo bien la clase ‘Aplication’ y por eso falla:

Macintosh:javafx josevnz$ ./piechart.py 
*sys-package-mgr*: can't create package cache dir, '/Users/Shared/jython2.5.2/cachedir/packages'
Traceback (most recent call last):
  File "./piechart.py", line 36, in 
    PieChartSample().launch(sys.argv[1:])
	at javafx.application.Application.launch(Application.java:186)
	at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
	at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)
	at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
	at java.lang.reflect.Method.invoke(Method.java:597)

java.lang.RuntimeException: java.lang.RuntimeException: Error: class sun.reflect.NativeMethodAccessorImpl is not a subclass of javafx.application.Application

No tengo ni idea en donde esta el error, ¿alguno de ustedes tiene una pista? De verdad me muero de ganas por usar JavaFX con Jython, ya otros han tenido éxito similar con JRuby y Groovy.

Amanecerá y veremos.

Actualización: De la lista de Jython me llegaron muchas sugerencias, al final Weiqi Gao encontró cual era el verdadero problema y esta es la solución:

# The key to happiness in JavaFX + Jython is this:
if __name__ == "__main__":
    Application.launch(PieChartSample().class, sys.argv[1:])

La explicación detallada a continuación:

The trick is with the last line of code that launches the application, which is accomplished with the javafx.application.Application.launch() method. There are two overloaded versions of this method:

public static void launch(String[] args);

and

public static void launch(Class< ? extends Application> appClass, String[] args);

The first version must be called from a method in a class that extends Application, which is not the case in the above python code. So we have to use the second version.

The idiom for using the first version of launch() in Java is the following:

public class Foo extends Application {
    @Override
    public void start(Stage stage) {
      // build the scene graph and show it
    }

    public static void main(String[] args) {
      Application.launch(args); 
    }
}

The idiom for using the second version of launch() in Java is the following:

public class Foo extends Application {
  @Override
  public void start(Stage stage) {
    // build the scene graph and show it
  }
}

public class Launcher {
  public static void main(String[] args) {
    Application.launch(Foo.class, args);
  }
}

There is an inefficiency in my python code in that I instantiated PieChartSample once only to get its class. I think there is a better way of doing it but can’t think of how at the moment.

One thought on “Jython + JavaFX: Comienzo duro

Comments are closed.