更新到Java 1.8u40后,JavaFx / Swing窗口无法打开

时间:2015-03-25 19:06:06

标签: java swing javafx

我们有一个主要在java 1.7开发并在1.8中测试的javafx应用程序。它运行正常,直到java 1.8u35。现在我们发现,升级后JavaFx窗口不会在1.8u40中打开。更糟糕的是,模态窗口阻止了整个标签/浏览器的使用。因此,用户只需使用任务管理器关闭浏览器即可。

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

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

更新

我查看了java1.8 here的已知问题列表。我可能只能链接到我们的问题是这个错误:

  

BUG-RT-32597:SwingNode类不支持高DPI显示。

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

之前是否有人遇到类似的问题并知道可能会有什么帮助?

更新

我试图更好地追查问题,但没有太多运气。 为了使其更加明显,这基本上是在窗口加载时发生的事情:

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.");

}

我认为执行会在某处停止,但它会照常运行整个函数。然而,窗户没有出现。

更新

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

围绕上述功能,会发生以下情况:

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类调用setVisible()方法时,应用程序被阻止但窗口不显示。实际上,在缩略图屏幕(alt + tab)中,它显示为应用程序内的容器。

删除setVisible调用时,浏览器不会被阻止,但窗口也不会显示。不幸的是,我没有找到要查找的JDialog类代码,setVisible()内部发生了什么。

任何想法,我们的设置或setVisible方法可能出错?

2 个答案:

答案 0 :(得分:1)

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

  1. 使用JDialog初始化模态JFXPanel(在Swing&#39的EDT上执行)
  2. 在FX任务中JFXPanel初始化并设置FX场景(在FX线程上执行)
  3. 等待FX任务完成(等待EDT)
  4. pack()show() JDialog(继续在EDT上阻止程序执行)
  5. 在用户关闭JDialog(在EDT上)后继续执行程序
  6. 我们使用此工作流程以等待某个用户输入以新模态JDialog显示,然后继续在EDT上执行正常的程序。

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

    在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(...),e。 G。通过设置一个恒定的大小或使用可以使用root.getBoundsInLocal()确定的FX场景的大小。

答案 1 :(得分:0)

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

我能够使用窗口监听器使dialog.pack()工作。

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