【问题标题】:JFXPanel setScene freezing with java 11JFXPanel setScene 使用 java 11 冻结
【发布时间】:2018-11-16 18:03:52
【问题描述】:

我想将 openjfx 集成到我的 Java 11 代码中。在 Windows 10 上使用 IntelliJ IDEA 2018.2.6,我创建了一个测试项目并尝试了以下代码

import javafx.embed.swing.JFXPanel;
import javafx.scene.Scene;
import javafx.scene.control.TabPane;

public class Java11FXTestApplication {



    public static void main(String[] args) {
        JFXPanel dummyPanel;
        TabPane dummyTabPane;
        Scene dummyScene;
        System.out.println("Creating JFX Panel");
        dummyPanel = new JFXPanel();
        System.out.println("Creating  TabPane");
        dummyTabPane = new TabPane();
        System.out.println("Creating  Scene");
        dummyScene = new Scene(dummyTabPane);
        System.out.println("Setting  Scene");
        dummyPanel.setScene(dummyScene); //Freezing here
        System.out.println("Scene Created");
    }
}

此代码在 setScene() 方法调用中冻结。 我尝试调试它,发现代码在 JFXPanel.setScene 方法中的 secondaryLoop.enter() 调用中无限期地等待。任何想法为什么?

此代码在 JDK-8 中运行良好,但不适用于 java-11.0.1。

我在这个问题上一无所获,有点卡在 Java11 JavaFX 问题上。代码有问题吗?或 java11 的 javafx 的任何报告问题

【问题讨论】:

  • 您使用的是哪个版本的openjfx?哪个模块/包导出类import javafx.embed.swing.JFXPanel;
  • 使用 openjfx-11.0.1_windows-x64_bin-sdk
  • @nullpointer JFXPaneljavafx.swing 模块导出。

标签: java windows java-11 openjfx


【解决方案1】:

您正在主线程上设置Scene。来自JFXPanel 的文档(强调我的):

有一些与JFXPanel 相关的限制。作为一个 Swing 组件,它只能从事件调度线程访问,除了setScene(javafx.scene.Scene) 方法,它可以在事件调度线程或 JavaFX 应用程序线程上调用。

setScene 包装在Platform.runLater 调用(或SwingUtilities.invokeLater)中。

Platform.runLater(() -> {
    dummyPanel.setScene(dummyScene);
    System.out.println("Scene Created");
});

请注意,使用您当前的代码,一旦main 返回,JVM 将继续运行。创建JFXPanel 会初始化JavaFX 运行时,该运行时在最后一个窗口关闭之前不会退出(仅当Platform.isImplicitExittrue 时)或调用Platform.exit。由于您的代码两者都没有,JavaFX 运行时将继续运行。


JFXPanel 的文档还提供了一个示例,说明了它的预期使用方式(注意几乎所有事情都发生在 Event Dispatch ThreadJavaFX 应用程序线程上) :

这是JFXPanel 可以如何使用的典型模式:

 public class Test {

     private static void initAndShowGUI() {
         // This method is invoked on Swing thread
         JFrame frame = new JFrame("FX");
         final JFXPanel fxPanel = new JFXPanel();
         frame.add(fxPanel);
         frame.setVisible(true);

         Platform.runLater(new Runnable() {
             @Override
             public void run() {
                 initFX(fxPanel);
             }
         });
     }

     private static void initFX(JFXPanel fxPanel) {
         // This method is invoked on JavaFX thread
         Scene scene = createScene();
         fxPanel.setScene(scene);
     }

     public static void main(String[] args) {
         SwingUtilities.invokeLater(new Runnable() {
             @Override
             public void run() {
                 initAndShowGUI();
             }
         });
     }
 }

【讨论】:

  • 该解决方案运行良好,并且解释得很好。我想知道为什么相同的代码在 java-8 而不是 java-11 中工作? JFX 从 java-8-fx 到 openjfx 的工作方式是否有重大变化?
  • 我怀疑在为 Java 9 模块化 JDK 和 JavaFX 库时发生了一些不错的变化。随着 JavaFX 11 与 JDK 的分离,他们也一直在消除对内部 Swing 代码的依赖——改用公共 API .因此,虽然我不知道细节,但如果实现没有至少有所改变,我会感到惊讶。此外,JFXPanel 的文档在 JavaFX 8 中是相同的,这意味着您可能只是走运了(或无意中依赖了一些实现细节)。
  • 似乎只有 Platform.runLater 在 Java 11 中有效,而在 SwingUtilities.invokeLater 中无效,SwingUtilities.invokeLater 在 Java 8 中也有效。
  • @StevenSpungin 如果这是真的那么这是一个错误,至少根据文档。
猜你喜欢
  • 1970-01-01
  • 2011-04-05
  • 2015-05-09
  • 2017-10-18
  • 2015-05-09
  • 2021-06-30
  • 2011-10-16
  • 2012-06-26
相关资源
最近更新 更多