gpt4 book ai didi

java - 防止 JavaFX 线程死于 JFXPanel Swing 互操作?

转载 作者:塔克拉玛干 更新时间:2023-11-03 04:20:25 24 4
gpt4 key购买 nike

我将几个 JFXPanels 嵌入到 Swing 应用程序中,当 JFXPanels 不再可见时,JavaFX 线程终止。这是有问题的,因为在 JavaFX 线程结束后创建另一个 JFXPanel 将不会启动另一个 JavaFX 线程,因此 JFXPanel 将为空白。

据我所知,JFXPanel ctor 通过调用启动 JavaFX 线程:

PlatformImpl.startup(new Runnable() {
@Override public void run() {
// No need to do anything here
}
});

稍后,一旦 JFXPanel 有一个父组件,它的 addNotify 方法就会被调用,它会调用 registerFinishListener 来注册一个 PlatformImpl.FinishListener ()PlatformImpl。注册 FinishListener 的行为可防止 JavaFX 线程在 PlatformImpl.checkIdle() 被调用时死亡。

JFXPanel 不再可见时,调用 removeNotify 方法调用 deregisterFinishListener():

private synchronized void deregisterFinishListener() {
if (instanceCount.decrementAndGet() > 0) {
// Other JFXPanels still alive
return;
}
PlatformImpl.removeListener(finishListener);
finishListener = null;
}

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

我发现解决此问题的唯一方法是在 Swing 应用程序开始时调用 Platform.setImplicitExit(false),这样 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;
}

我错过了什么吗?

最佳答案

这是一个非常古老的“错误”,随着 Platform.setImplicitExit(false) 的引入而得到修复。您可以在 Unresolved 问题中阅读开发人员的评论 JDK-8090517 .正如您将看到的那样,它的优先级很低,可能永远不会得到修复(至少不会很快)。

您可能想要尝试而不是使用 Platform.setImplicitExit(false) 的另一种解决方案是扩展当前 Main 类中的 Application 类并使用主 Stage 来显示应用程序的主窗口。只要 primary Stage 保持打开状态,FX Thread 就会处于 Activity 状态(并在您关闭应用程序时正确处理)。

如果您不想使用 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();
}

请记住,伪造一个初级阶段(或将您的主窗口迁移到 FX)将以更多代码结束,而不是简单地使用 Platform.setImplicitExit(false)Platform.exit() 相应地。

无论如何,希望这对您有所帮助!

关于java - 防止 JavaFX 线程死于 JFXPanel Swing 互操作?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/25193198/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com