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:
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 31 32 33 34 35 | 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:
1 2 3 | 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 gráfico de torta en acción
Así que traté de convertir este sencillo código a Jython:
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 31 32 33 34 35 36 | #!/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:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 | 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 <module> 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 </module> |
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:
1 2 3 | # 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:
1 public static void launch(String[] args);and
1 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:
1 2 3 4 5 6 7 8 9 10 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:
1 2 3 4 5 6 7 8 9 10 11 12 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.
Comentarios recientes