私のアプリケーションは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番目の方法を使用しました。
ソリューションを見つけました。 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();
}
});
}
});
}
}
JavaFXを使用する唯一の方法は、アプリケーションとサブクラスを作成するか、JFXPanelを使用することです。まさに、envとツールキットを準備するからです。
ブロッキングスレッドは、new Thread(...)
を使用して解決できます。
Swing/AWTと同じVMでJavaFXを使用している場合はJFXPanelを使用することをお勧めしますが、詳細はこちらで確認できます: JavaFxでAWTを使用しても大丈夫ですか?
私はソースコードをチェックし、これはそれを初期化することです
com.Sun.javafx.application.PlatformImpl.startup(()->{});
そしてそれを終了する
com.Sun.javafx.application.PlatformImpl.exit();
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
}
}
この投稿はテスト関連ではありませんが、ユニットテストを機能させるのに役立ちました
次を呼び出して、ツールキットを明示的に初期化する方法もあります:com.Sun.javafx.application.PlatformImpl#startup(Runnable)
* Implを使用しているため少しハックしますが、何らかの理由でApplication
またはJXFPanel
を使用したくない場合に便利です。
この投稿から自分自身を再投稿する
JavaFX 9以降、 Application
クラスを拡張せずに Platform.startup()
を呼び出すことにより、JavaFXアプリケーションを実行できます。
Platform.startup(() ->
{
// This block will be executed on JavaFX Thread
});
このメソッドは、JavaFXランタイムを開始します。
_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)
がキーです。