JavaFX 2.1: Toolkit not initialized

匿名 (未验证) 提交于 2019-12-03 02:06:01

问题:

My application is Swing-based. I would like to introduce JavaFX and configure it to render a Scene on a secondary display. I could use a JFrame to hold a JFXPanel which could hold a JFXPanel but I would like to achieve this with JavaFX API.

Subclassing com.sun.glass.ui.Application and using Application.launch(this) is not an option because the invoking thread would be blocked.

When instantiating a Stage from Swing EDT, the error I get is:

java.lang.IllegalStateException: Toolkit not initialized 

Any pointers?


EDIT: Conclusions

Problem: Non-trivial Swing GUI application needs to run JavaFX components. Application's startup process initializes the GUI after starting up a dependent service layer.

Solutions

Subclass JavaFX Application class and run it in a separate thread e.g.:

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

Sidenote: Because Application.launch() method takes a Class extends Application> as an argument, one has to use a global variable to signal JavaFX environment has been initialized.

Alternative approach: instantiate JFXPanel in 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(); 

By using this approach the calling thread will wait until JavaFX environment is set up.

Pick any solution you see fit. I went with the second one because it doesn't need a global variable to signal the initialization of JavaFX environment and also doesn't waste a thread.

回答1:

The only way to work with JavaFX is to subclass Application or use JFXPanel, exactly because they prepare env and toolkit.

Blocking thread can be solved by using new Thread(...).

Although I suggest to use JFXPanel if you are using JavaFX in the same VM as Swing/AWT, you can find more details here: Is it OK to use AWT with JavaFx?



回答2:

Found a solution. If I just create a JFXPanel from Swing EDT before invoking JavaFX Platform.runLater it works. I don't know how reliable this solution is, I might choose JFXPanel and JFrame if turns out to be unstable.

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();                     }                 });             }         });     } } 


回答3:

I used following when creating unittests for testing javaFX tableview updates

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          }     } 

even though this post is not test related, then it helped me to get my unittest to work

  • without the BeforeClass initToolkit, then the instantiation of TableView in the unittest would yield a message of missing toolkit


回答4:

There's also way to initialize toolkit explicitly, by calling: com.sun.javafx.application.PlatformImpl#startup(Runnable)

Little bit hacky, due to using *Impl, but is useful, if you don't want to use Application or JXFPanel for some reason.

re-posting myself from this post



回答5:

I checked the source code and this is to initialize it

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

and to exit it

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


易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!