web-dev-qa-db-ja.com

JavaFX 2.1:ツールキットが初期化されていません

私のアプリケーションはSwingベースです。 JavaFXを導入し、セカンダリディスプレイでシーンをレンダリングするように構成したいと思います。 JFrameを使用してJFXPanelを保持できるJFXPanelを保持できましたが、JavaFX APIでこれを実現したいと思います。

Com.Sun.glass.ui.Applicationをサブクラス化し、Application.launch(this)を使用することは、呼び出しスレッドがブロックされるため、オプションではありません。

Swing EDTからステージをインスタンス化すると、次のエラーが表示されます。

Java.lang.IllegalStateException: Toolkit not initialized

ポインタはありますか?


編集:結論

問題:重要でないSwing GUIアプリケーションはJavaFXコンポーネントを実行する必要があります。アプリケーションの起動プロセスは、依存サービスレイヤーの起動後にGUIを初期化します。

ソリューション

サブクラスJavaFXアプリケーションクラスそして別のスレッドで実行します。例:

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

補足:Application.launch()メソッドはClass<? extends Application>は引数として、グローバル変数を使用してJavaFX環境が初期化されたことを通知する必要があります。

代替アプローチ:Swing Event Dispatcher ThreadのJFXPanelのインスタンス化

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

このアプローチを使用することにより、呼び出しスレッドはJavaFX環境がセットアップされるまで待機します。

適切なソリューションを選択してください。 JavaFX環境の初期化を通知するためにグローバル変数を必要とせず、スレッドを浪費しないため、2番目の方法を使用しました。

54
Dan Vulpe

ソリューションを見つけました。 JavaFX Platform.runLaterを呼び出す前にSwing EDTからJFXPanelを作成するだけで機能します。このソリューションの信頼性はわかりません。不安定であることが判明した場合は、JFXPanelとJFrameを選択できます。

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<WindowEvent>() {
                                    @Override
                                    public void handle(WindowEvent windowEvent) {
                                        System.exit(0);
                                    }
                                })
                                .build()
                                .show();
                    }
                });
            }
        });
    }
}
21
Dan Vulpe

JavaFXを使用する唯一の方法は、アプリケーションとサブクラスを作成するか、JFXPanelを使用することです。まさに、envとツールキットを準備するからです。

ブロッキングスレッドは、new Thread(...)を使用して解決できます。

Swing/AWTと同じVMでJavaFXを使用している場合はJFXPanelを使用することをお勧めしますが、詳細はこちらで確認できます: JavaFxでAWTを使用しても大丈夫ですか?

22
Sergey Grinev

私はソースコードをチェックし、これはそれを初期化することです

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

そしてそれを終了する

com.Sun.javafx.application.PlatformImpl.exit();
5
user28775

JavaFX tableviewの更新をテストするための単体テストを作成するときに、以下を使用しました

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<yourclassDefiningEntries> yourTable = new TableView<>();
            .... do your testing stuff

        }
    }

この投稿はテスト関連ではありませんが、ユニットテストを機能させるのに役立ちました

  • beforeClass initToolkitがない場合、unittestでTableViewをインスタンス化すると、ツールキットが見つからないというメッセージが生成されます。
4
serup

次を呼び出して、ツールキットを明示的に初期化する方法もあります:com.Sun.javafx.application.PlatformImpl#startup(Runnable)

* Implを使用しているため少しハックしますが、何らかの理由でApplicationまたはJXFPanelを使用したくない場合に便利です。

この投稿から自分自身を再投稿する

4
krzychek

JavaFX 9以降、 Application クラスを拡張せずに Platform.startup() を呼び出すことにより、JavaFXアプリケーションを実行できます。

Platform.startup(() ->
{
    // This block will be executed on JavaFX Thread
});

このメソッドは、JavaFXランタイムを開始します。

3
Eng.Fouad
_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");
}
_

これが私の解決策です。クラスの名前はMainで、Runnableを実装します。メソッドstartup(Runnable r)がキーです。

0
Jack Lin