简体   繁体   English

Swing JFrame导致JavaFX应用程序在OS X上崩溃

[英]Swing JFrame causes JavaFX application to crash on OS X

I'm working on a complex JavaFX project that is supposed to include Swing JFrames. 我正在开发一个复杂的JavaFX项目,它应该包含Swing JFrames。 Everything works fine, the JFrames however refuse to close under certain conditions, locking up the entire VM. 一切正常,JFrame然而在某些条件下拒绝关闭,锁定整个VM。 I've boiled everything down to a minimum working example, which seems to work on Windows (please confirm if it works on your machine) but crashes OS X reliably. 我把所有东西都煮到了最低限度的工作示例,这似乎适用于Windows(请确认它是否适用于您的计算机)但可靠地崩溃OS X. I'm using Java 8u25 (latest stable) and 8u40 preview (latest build) - no difference. 我正在使用Java 8u25(最新稳定版)和8u40预览版(最新版本) - 没有区别。

How to reproduce : Save the program as "JavaFXWithJFrames.java", compile & run it. 如何重现 :将程序保存为“JavaFXWithJFrames.java”,编译并运行它。 There are now 3 Swing JFrames and 1 JavaFX Window with 3 Buttons. 现在有3个Swing JFrame和1个带3个按钮的JavaFX窗口。 Clicking the Buttons should close 1 of the windows, respectively. 单击按钮应分别关闭其中一个窗口。 This works on Windows(?) but completely locks up the program on OS X (and maybe other OSs?) 这适用于Windows(?),但完全锁定OS X上的程序(可能还有其他操作系统?)

Can you reproduce this? 你能复制一下吗? Yes/No, Which machine/OS/JRE? 是/否,哪台机器/ OS / JRE? What am I doing wrong here - threading issues? 我在这里做错了什么 - 线程问题? Thanks so much for your help. 非常感谢你的帮助。

Code on pastebin: http://pastebin.com/tUrdNfCw# - please save as "JavaFXWithJFrames.java" to compile! 关于pastebin的代码: http ://pastebin.com/tUrdNfCw# - 请保存为“JavaFXWithJFrames.java”进行编译!

/*
 * To change this license header, choose License Headers in Project Properties.
 * To change this template file, choose Tools | Templates
 * and open the template in the editor.
 */
//package javafxwithjframes;

import javafx.application.Application;
import javafx.event.ActionEvent;
import javafx.event.EventHandler;
import javafx.scene.Scene;
import javafx.scene.control.Button;
import javafx.scene.layout.HBox;
import javafx.stage.Stage;
import javafx.stage.WindowEvent;
import javax.swing.JFrame;

/**
 * When starting, a JavaFX window and 3 Swing JFrame-windows appear.
 * The JavaFX window features 3 buttons that each are supposed to close one of the JFrames.
 * The program, however, freezes after clicking a button. What am I doing wrong?
 * It seems to work on Windows, but crash on OS X 10.10.1, using Java 8u25 (latest release) and Java 8u40 Dec 31 preview-build.
 *
 * @author a desperate developer
 */
public class JavaFXWithJFrames extends Application {

JFrame jframe1, jframe2, jframe3;

@Override
public void start(Stage primaryStage) {

    // Create 3 JFrames
    jframe1 = new JFrame("JFrame 1");
    jframe1.setBounds(50, 50, 200, 150);
    jframe1.setVisible(true);

    jframe2 = new JFrame("JFrame 2");
    jframe2.setBounds(275, 50, 200, 150);
    jframe2.setVisible(true);

    jframe3 = new JFrame("JFrame 3");
    jframe3.setBounds(500, 50, 200, 150);
    jframe3.setVisible(true);

    // Create 3 buttons that close each one JFrame
    // Button 1
    Button closeButton1 = new Button();
    closeButton1.setText("Close JFrame 1");
    closeButton1.setOnAction(new EventHandler<ActionEvent>() {
        @Override
        public void handle(ActionEvent event) {
            jframe1.setVisible(false);
            System.out.print("Closing JFrame 1...");
            jframe1.dispose();
        }
    });

    // Button 2
    Button closeButton2 = new Button();
    closeButton2.setText("Close JFrame 2");
    closeButton2.setOnAction(new EventHandler<ActionEvent>() {
        @Override
        public void handle(ActionEvent event) {
            jframe2.setVisible(false);
            System.out.print("Closing JFrame 2...");
            jframe2.dispose();
        }
    });

    // Button 3
    Button closeButton3 = new Button();
    closeButton3.setText("Close JFrame 3");
    closeButton3.setOnAction(new EventHandler<ActionEvent>() {
        @Override
        public void handle(ActionEvent event) {
            jframe3.setVisible(false);
            System.out.print("Closing JFrame 3...");
            jframe3.dispose();
        }
    });

    // Setting up main window
    HBox rootBox = new HBox();
    rootBox.getChildren().addAll(closeButton1, closeButton2, closeButton3);
    Scene scene = new Scene(rootBox, 400, 250);
    primaryStage.setOnCloseRequest(new EventHandler<WindowEvent>() {
        @Override
        public void handle(WindowEvent event) {
            System.exit(0);
        }
    });
    primaryStage.setTitle("JavaFX with JFrames");
    primaryStage.setScene(scene);
    primaryStage.show();
}

/**
 * @param args the command line arguments
 */
public static void main(String[] args) {
    launch(args);
}

}

You have a threading issue here: you are doing everything on the FX Application Thread, whereas the Swing work should be on the AWT event dispatch thread. 你有一个线程问题:你正在FX应用程序线程上做所有事情,而Swing工作应该在AWT事件派发线程上。

You can schedule code to run on the AWT event handling thread using SwingUtilities.invokeLater(...); 您可以使用SwingUtilities.invokeLater(...);安排代码在AWT事件处理线程上运行SwingUtilities.invokeLater(...); .

So your code should look like 所以你的代码应该是这样的

@Override
public void start(Stage primaryStage) {

    SwingUtilities.invokeLater( () -> {
        // Create 3 JFrames
        jframe1 = new JFrame("JFrame 1");
        jframe1.setBounds(50, 50, 200, 150);
        jframe1.setVisible(true);

        jframe2 = new JFrame("JFrame 2");
        jframe2.setBounds(275, 50, 200, 150);
        jframe2.setVisible(true);

        jframe3 = new JFrame("JFrame 3");
        jframe3.setBounds(500, 50, 200, 150);
        jframe3.setVisible(true);
    });

    // Create 3 buttons that close each one JFrame
    // Button 1
    Button closeButton1 = new Button();
    closeButton1.setText("Close JFrame 1");
    closeButton1.setOnAction(event -> {
        SwingUtilities.invokeLater(() -> {
            jframe1.setVisible(false);
            System.out.print("Closing JFrame 1...");
            jframe1.dispose();
        });
    });

    // similarly for other button handlers...

}

(I changed your event handler to a lambda expression as the nested inner classes are simply too ugly, and you said you were using JDK 8...) (我将事件处理程序更改为lambda表达式,因为嵌套的内部类太简单了,你说你使用的是JDK 8 ...)

You can also try running your application as it is, but with the experimental system property 您也可以尝试按原样运行应用程序,但使用实验系统属性

-Djavafx.embed.singleThread=true

This runs both UI toolkits on the same thread. 这在同一个线程上运行两个UI工具包。 Since (to the best of my knowledge) this is still experimental, I would recommend scheduling the code on the "correct" threads as shown above. 由于(据我所知)这仍然是实验性的,我建议在“正确”的线程上安排代码,如上所示。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM