jen*_*ert 7 java swing interop javafx javafx-8
我将几个嵌入JFXPanels到Swing应用程序中,当JFXPanel不再可见时,JavaFX线程就会死掉.这是有问题的,因为JFXPanel在JavaFX线程死后创建另一个将不会启动另一个JavaFX线程,因此JFXPanel将为空.
据我所知,JFXPanel ctor通过调用以下命令启动JavaFX线程:
PlatformImpl.startup(new Runnable() {
@Override public void run() {
// No need to do anything here
}
});
Run Code Online (Sandbox Code Playgroud)
后来一旦JFXPanel有父组件的addNotify方法调用它调用registerFinishListener一个注册到PlatformImpl.FinishListener()使用PlatformImpl.注册的行为FinishListener可以防止JavaFX线程在PlatformImpl.checkIdle()被调用时死亡.
当a JFXPanel不再可见时,其removeNotify方法是调用调用deregisterFinishListener():
private synchronized void deregisterFinishListener() {
if (instanceCount.decrementAndGet() > 0) {
// Other JFXPanels still alive
return;
}
PlatformImpl.removeListener(finishListener);
finishListener = null;
}
Run Code Online (Sandbox Code Playgroud)
当instanceCount为零时,FinishListener将删除导致PlatformImpl调用PlatformImpl.tkExit以下代码导致JavaFX线程死亡:
private static void notifyFinishListeners(boolean exitCalled) {
// Notify listeners if any are registered, else exit directly
if (listenersRegistered.get()) {
for (FinishListener l : finishListeners) {
if (exitCalled) {
l.exitCalled();
} else {
l.idle(implicitExit);
}
}
} else if (implicitExit || platformExit.get()) {
tkExit();
}
}
Run Code Online (Sandbox Code Playgroud)
我发现修复此问题的唯一方法是Platform.setImplicitExit(false)在Swing应用程序的开头调用,以便JavaFX线程永远不会自动死亡.此修复需要Platform.exit()在应用程序退出时调用,否则JavaFX线程将阻止进程停止.
这似乎是JavaFX-Swing互操作中的一个错误,或者至少应该修改互操作文档以通过讨论来解决这个问题Platform.setImplicitExit(false).
另一个解决方案是允许在创建另一个JFXPanel时创建一个新的JavaFX线程但是被以下命令阻止PlatformImpl.startup(Runnable):
if (initialized.getAndSet(true)) {
// If we've already initialized, just put the runnable on the queue.
runLater(r);
return;
}
Run Code Online (Sandbox Code Playgroud)
我错过了什么吗?
这是一个非常古老的"错误",随着引入而有所修复Platform.setImplicitExit(false).您可以在公开发行的JDK-8090517中阅读开发人员的评论.正如您将看到它具有低优先级,并且可能永远不会得到修复(至少不会很快).
您可能想要尝试而不是使用的另一种解决方案Platform.setImplicitExit(false)是在当前Main类中扩展Application类,并使用主Stage显示应用程序的主窗口.只要主要舞台保持打开状态,FX Thread将处于活动状态(并在关闭应用程序时正确处理).
如果您不打算使用FX Stage作为主窗口(因为它需要使用SwingNode来实现您现有的功能或将UI迁移到JavaFX),您可以随意假冒这样的:
@Override
public void start(Stage primaryStage) throws Exception {
YourAppMainWindow mainWindow = new YourAppMainWindow();
// Load your main window Swing Stuff (remember to use
// SwingUtilities.invokeLater() to run inside the Event Dispatch Thread
mainWindow.initSwingUI();
// Now that the Swing stuff is loaded open a "hidden" primary stage
// that will keep the FX Thread alive
primaryStage.setWidth(0);
primaryStage.setHeight(0);
primaryStage.setX(Double.MAX_VALUE);
primaryStage.setY(Double.MAX_VALUE);
primaryStage.initStyle(StageStyle.UTILITY);
primaryStage.show();
}
Run Code Online (Sandbox Code Playgroud)
请记住,伪造主要阶段(或将主窗口迁移到FX)将以更多代码而不是简单地使用Platform.setImplicitExit(false)并Platform.exit()相应地结束.
无论如何,希望这有帮助!
| 归档时间: |
|
| 查看次数: |
2150 次 |
| 最近记录: |