我正在处理一个应该包含 Swing JFrames 的复杂 JavaFX 项目。一切正常,但 JFrames 在某些情况下拒绝关闭,从而锁定了整个 VM。 我已经将所有内容归结为一个最小的工作示例,它似乎可以在 Windows 上工作(请确认它是否可以在您的机器上工作)但可靠地使 OS X 崩溃。我使用的是 Java 8u25(最新稳定版)和 8u40 预览版(最新版本)——没有区别。
如何重现:将程序保存为“JavaFXWithJFrames.java”,编译并运行它。现在有 3 个 Swing JFrames 和 1 个带有 3 个按钮的 JavaFX 窗口。单击按钮应分别关闭其中一个窗口。 这适用于 Windows(?),但在 OS X(可能还有其他操作系统?)上会完全锁定程序
你能重现吗?是/否,哪台机器/操作系统/JRE?我在这里做错了什么 - 线程问题? 非常感谢您的帮助。
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);
}
}
最佳答案
这里有一个线程问题:您在 FX 应用程序线程上执行所有操作,而 Swing 工作应该在 AWT 事件调度线程上进行。
您可以使用 SwingUtilities.invokeLater(...);
安排代码在 AWT 事件处理线程上运行。
所以你的代码应该是这样的
@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...
}
(我将您的事件处理程序更改为 lambda 表达式,因为嵌套内部类太丑陋了,而且您说您使用的是 JDK 8...)
您也可以尝试按原样运行您的应用程序,但使用实验性系统属性
-Djavafx.embed.singleThread=true
这会在同一个线程上运行两个 UI 工具包。由于(据我所知)这仍然是实验性的,我建议将代码安排在“正确”的线程上,如上所示。
关于java - Swing JFrame 导致 JavaFX 应用程序在 OS X 上崩溃,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/27826874/