JavaFX 2.1: Toolkit no inicializado

Mi aplicación está basada en Swing. Me gustaría presentar JavaFX y configurarlo para representar una escena en una pantalla secundaria. Podría usar un JFrame para contener un JFXPanel que podría contener un JFXPanel, pero me gustaría lograrlo con la API de JavaFX.

La subclasificación de com.sun.glass.ui.Application y el uso de Application.launch (this) no es una opción porque el hilo de invocación se bloquearía.

Al crear una instancia de Stage desde Swing EDT, el error que obtengo es:

java.lang.IllegalStateException: Toolkit not initialized 

¿Alguna sugerencia?


EDITAR: Conclusiones

Problema : la aplicación de GUI Swing no trivial necesita ejecutar componentes JavaFX. El proceso de inicio de la aplicación inicializa la GUI después de iniciar una capa de servicio dependiente.

Soluciones

Subclase clase de aplicación JavaFX y ejecútelo en una secuencia separada, por ejemplo:

 public class JavaFXInitializer extends Application { @Override public void start(Stage stage) throws Exception { // JavaFX should be initialized someGlobalVar.setInitialized(true); } } 

Sidenote: Porque el método Application.launch () toma una Class Class como argumento, uno tiene que usar una variable global para indicar que el entorno JavaFX se ha inicializado.

Enfoque alternativo: crea una instancia de JFXPanel en Swing Event Dispatcher Thread :

 final CountDownLatch latch = new CountDownLatch(1); SwingUtilities.invokeLater(new Runnable() { public void run() { new JFXPanel(); // initializes JavaFX environment latch.countDown(); } }); latch.await(); 

Al utilizar este enfoque, el hilo de llamada esperará hasta que se configure el entorno JavaFX.

Elija cualquier solución que considere adecuada. Fui con el segundo porque no necesita una variable global para señalar la inicialización del entorno JavaFX y tampoco desperdicia un hilo.

La única forma de trabajar con JavaFX es subclasificar la aplicación o usar JFXPanel, exactamente porque preparan el env y el toolkit.

El locking del hilo se puede resolver utilizando un new Thread(...) .

Aunque sugiero usar JFXPanel si está utilizando JavaFX en la misma máquina virtual que Swing / AWT, puede encontrar más detalles aquí: ¿Está bien utilizar AWT con JavaFx?

Encontré una solución. Si solo creo un JFXPanel desde Swing EDT antes de invocar JavaFX Platform.runLater, funciona. No sé qué tan confiable es esta solución, podría elegir JFXPanel y JFrame si resulta ser inestable.

 public class BootJavaFX { public static void main(String[] args) { SwingUtilities.invokeLater(new Runnable() { @Override public void run() { new JFXPanel(); // this will prepare JavaFX toolkit and environment Platform.runLater(new Runnable() { @Override public void run() { StageBuilder.create() .scene(SceneBuilder.create() .width(320) .height(240) .root(LabelBuilder.create() .font(Font.font("Arial", 54)) .text("JavaFX") .build()) .build()) .onCloseRequest(new EventHandler() { @Override public void handle(WindowEvent windowEvent) { System.exit(0); } }) .build() .show(); } }); } }); } } 

Revisé el código fuente y esto es para inicializarlo

 com.sun.javafx.application.PlatformImpl.startup(()->{}); 

y para salir de ella

 com.sun.javafx.application.PlatformImpl.exit(); 

Utilicé los siguientes para crear pruebas unitarias para probar las actualizaciones de la vista de tabla javaFX

 public class testingTableView { @BeforeClass public static void initToolkit() throws InterruptedException { final CountDownLatch latch = new CountDownLatch(1); SwingUtilities.invokeLater(() -> { new JFXPanel(); // initializes JavaFX environment latch.countDown(); }); if (!latch.await(5L, TimeUnit.SECONDS)) throw new ExceptionInInitializerError(); } @Test public void updateTableView() throws Exception { TableView yourTable = new TableView<>(); .... do your testing stuff } } 

aunque esta publicación no está relacionada con las pruebas, me ayudó a hacer que mi prueba unitaria funcione

  • sin el BeforeClass initToolkit, entonces la creación de instancias de TableView en el unittest arrojaría un mensaje de falta de toolkit

También hay forma de inicializar el kit de herramientas explícitamente, llamando a: com.sun.javafx.application.PlatformImpl#startup(Runnable)

Un poco hacky, debido al uso de * Impl, pero es útil, si no quieres usar Application o JXFPanel por alguna razón.

volviendo a publicarme desde esta publicación

 private static Thread thread; public static void main(String[] args) { Main main = new Main(); startup(main); thread = new Thread(main); thread.start(); } public static void startup(Runnable r) { com.sun.javafx.application.PlatformImpl.startup(r); } @Override public void run() { SoundPlayer.play("BelievexBelieve.mp3"); } 

Esta es mi solución. La clase se llama Principal e implementa Runnable. El startup(Runnable r) método startup(Runnable r) es la clave.