JavaFx/ Swing window 更新到 Java 1.8u40 后打不开

JavaFx/ Swing window does not open after update to Java 1.8u40

我们有一个主要在 java 1.7 开发并在 1.8 测试的 javafx 应用程序。在 java 1.8u35 之前 运行 还好。现在我们发现,升级后 JavaFx windows 将不会在 1.8u40 中打开。更糟糕的是,模态 windows 会阻止使用整个选项卡/浏览器。所以用户只能使用任务管理器关闭浏览器。

我们使用 javafx.embed.swing.JFXPanel 将 jfx 代码嵌入到 swing 遗留代码中。

我完全不知道可能是什么问题,因为客户端的 java 控制台中没有显示任何错误。

更新:

我查看了 java1.8 here 的已知问题列表。对于我们的问题,我唯一可能 link 就是这个错误:

BUG-RT-32597: The SwingNode class does not support High DPI displays.

所以我尝试降低屏幕分辨率(1280x1024 到 800x600)但没有成功。

有没有人以前遇到过类似的问题并且知道什么可以帮助?

更新:

我试图更好地找出问题所在,但运气不佳。 为了让它更显眼,这基本上就是 window loading:

上发生的事情
public static void initWindow(JDialog dialog){

    final JFXPanel jfx = new JFXPanel();
    Platform.runLater(new Runnable() {
        public void run() {
            System.out.println("JFXPanel");
        }
    });

    Runnable r = new Runnable() {
        public void run() {

            AnchorPane root = new AnchorPane;
            //... do some content loading

            Scene scene = new Scene(root,width,height);
            System.out.println("test");
        }
    };

    dialog.add(jfx);
    System.out.println("added jfx panel.");

    dialog.pack();
    System.out.println("packed jfx panel.");

    dialog.setLocationRelativeTo(null);
    System.out.println("loaded.");

}

我以为执行会在某个地方停止,但 运行 整个函数照常执行。然而 window 没有出现。

更新:

不完全正确,我最后的评论,正如我发现的那样:

围绕上述函数,会发生以下情况:

initWindow(this); //this is extending java.swing.JDialog
System.out.println("this comment is printed to console");
super.setVisible(true); //this is not executed properly. if removed, browser will not be blocked, but window doesnt show up either
System.out.println("this comment is not printed to console";

因此,一般来说,JDialog 与 JfxPanel 打包在一起。从 JDialog class 调用 setVisible() 方法时,应用程序被阻止但 window 未显示。实际上,在缩略图屏幕 (alt+tab) 中,它显示为应用程序内部的容器。

删除 setVisible 调用时,浏览器不会被阻止,而且 window 也不会显示。不幸的是,我没有找到 JDialog class 代码来查找,setVisible().

内部发生了什么

任何想法,我们的设置或 setVisible 方法可能有什么问题?

我们遇到了类似的问题。在比较 1.8.0_31 和 1.8.0_45 的 Java 源代码时,我们发现 1.8.[=54= 引入的 JFXPanel 源代码有一些变化。 ] 在以下情况下可能会出现问题:

  1. JFXPanel初始化模态JDialog(在Swing的EDT上执行)
  2. 在 FX 任务(在 FX 线程上执行)JFXPanel 上初始化并设置 FX 场景
  3. 等待 FX 任务完成(等待 EDT)
  4. pack()show() JDialog(美国东部时间继续,阻止程序执行)
  5. 在用户关闭后继续执行程序 JDialog(美国东部时间)

我们使用此工作流程是为了等待一些用户输入以新模式显示 JDialog 并在之后继续在 EDT 上正常执行程序。

在 1.8.0_31 中,JFXPanel 的首选大小似乎是在允许 JDialog.pack() 确定正确边界的 FX 线程中设置的。

在 1.8.0_45 中,JFXPanel 的首选大小似乎不再在 FX 线程中设置,而是在执行所有未决 AWT 事件后在 EDT 中设置。因此,当执行 (4) 时,JDialog.pack() 不知道场景的首选大小。因此,对话框没有内容,或者如果未按照上述原始问题中的描述进行修饰,则不会显示。

这是重现不同行为的完整示例:

public static void main(String[] args) {
    SwingUtilities.invokeLater(new Runnable() {
        public void run() {

            // create JDialog on EDT
            final JDialog dialog = new JDialog((JDialog)null, "JDialog");

            // initialize FX platform and create JFXPanel
            final JFXPanel jfxPanel = new JFXPanel();

            // add resize listener for JFXPanel
            jfxPanel.addComponentListener(new ComponentAdapter() {
                public void componentResized(ComponentEvent e) {
                    // not called in 1.8.0_45
                    System.out.println("JFXPanel.getSize(): "+jfxPanel.getSize());
                }
            });

            // set FX Scene on JFXPanel and wait until finished
            runAndWait(new Runnable() {                
                public void run() {
                    Text text = TextBuilder.create().text("JavaFx content").y(20).build();
                    Group root = new Group(text);
                    Scene scene = new Scene(root);
                    jfxPanel.setScene(scene);
                }
            });

            // show undecorated modal JDialog with FX content
            System.out.println("JFXPanel.getPreferredSize(): "+jfxPanel.getPreferredSize());
            dialog.setUndecorated(true);
            dialog.add(jfxPanel);
            dialog.pack();
            dialog.setModal(true);
            System.out.println("JDialog.setVisible()");
            dialog.setVisible(true);
        }
    });
}

private static void runAndWait(Runnable r) {
    try {
        FutureTask<Object> task = new FutureTask<Object>(r, null);
        Platform.runLater(task);
        task.get();
    }
    catch (Exception e) {
        throw new RuntimeException(e);
    }
}

当运行此程序时,componentResized()仅在1.8.0_31中被调用,而在1.8.0_45.

中不被调用

在 EDT 上保持同步程序工作流程的一个可能的修复方法是将 JDialog.pack() 替换为 JDialog.setSize(...),例如。 G。通过设置恒定大小或使用可以使用 root.getBoundsInLocal().

确定的 FX 场景的大小

我遇到了@Peter 使用 1.8 描述的相同行为。0_121。

我能够使用 window 侦听器让 dialog.pack() 工作。

dialog.addWindowListener( new WindowAdapter() {
    @Override
    public void windowOpened(WindowEvent e) {
        ((JDialog)e.getSource()).pack();
    }    
});