66

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

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

Swing EDTからステージをインスタンス化すると、次のエラーが発生します。

java.lang.IllegalStateException: Toolkit not initialized

ポインタはありますか?


編集:結論

問題:重要なSwingGUIアプリケーションは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スレッドで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番目のものを使用しました。

4

8 に答える 8

23

解決策を見つけました。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();
                    }
                });
            }
        });
    }
}
于 2012-06-30T20:19:15.857 に答える
21

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

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

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

于 2012-06-30T16:27:24.260 に答える
18

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

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

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

于 2018-12-13T10:58:01.827 に答える
8

ソースコードを確認しましたが、これは初期化するためのものです

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

そしてそれを終了するには

com.sun.javafx.application.PlatformImpl.exit();
于 2017-10-26T14:11:14.017 に答える
4

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

        }
    }

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

  • BeforeClass initToolkitがないと、単体テストでTableViewをインスタンス化すると、ツールキットが見つからないというメッセージが表示されます。
于 2016-07-13T07:41:59.223 に答える
4

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

* Implを使用しているため、少しハッキーですが、使用したくない場合ApplicationJXFPanel何らかの理由で便利です。

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

于 2016-08-10T21:04:46.563 に答える
0
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)が鍵です。

于 2018-05-12T02:11:40.170 に答える
0

Jack Linの答えを使用して、run()が2回起動したことがわかりました。答えをより簡潔にするいくつかの変更を加えて、私は以下を提供します。

import com.sun.javafx.application.PlatformImpl;

public class MyFxTest implements Runnable {

    public static void main(String[] args) {

        MyFxTest main = new MyFxTest();
        PlatformImpl.startup((Runnable) main);
    }

    @Override
    public void run() {

        // do your testing;
        System.out.println("Here 'tis");
        System.exit(0); // Optional
    }
}
于 2021-09-28T22:49:01.180 に答える