我目前正在开发一个使用基于swing的框架的项目。我的目标是为这个项目添加一个JavaFX组件,但是我遇到了模态对话框的一些问题。
总的来说,我的问题可以简化如下 -
Swing:我有一个包含按钮的JFrame
。当我按下这个按钮时,我想打开一个包含一些JavaFX代码的对话框。这个新对话框应该阻止并始终位于框架的顶部。
JavaFX:这里我也有一个按钮。当我按下此按钮时,我想显示一个Alert
,它应该阻止对话框(因此也会阻止Swing JFrame)。
目前我的解决方案是使用JDialog
包含JFXPanel
作为"胶水"总的来说我的逻辑如下
JFrame
包含一个用于打开新JDialog
JDialog
包含JFXPanel
,其中包含一个包含JavaFX Scene
Button
Button
会打开Alert
代码位于这篇文章的底部。
目前JDialog
按预期工作。它会阻止父框架并始终位于其上面。
Dialog
并不像预期的那样有效。它会阻止JavaFX Scene
(我无法多次按下该按钮),但它在JDialog
方面存在一些问题。这些是 -
JDialog
带到警报前面JDialog
醇>
我自己的理论是问题是JDialog
和JFXPanel
之间的关系。但我不太确定如何将它们联系起来。
一个快速而又肮脏的例子:
package test;
import java.awt.Dialog.ModalityType;
import java.awt.Frame;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.lang.reflect.Field;
import java.util.logging.Level;
import java.util.logging.Logger;
import javafx.application.Platform;
import javafx.embed.swing.JFXPanel;
import javafx.event.EventHandler;
import javafx.scene.Scene;
import javafx.scene.control.Alert;
import javafx.scene.control.Alert.AlertType;
import javafx.scene.control.Button;
import javafx.scene.layout.StackPane;
import javafx.stage.Modality;
import javafx.stage.Window;
import javax.swing.JButton;
import javax.swing.JDialog;
import javax.swing.JFrame;
public class TestFXInSwing {
private static void createAndShowGUI() {
JFrame frame = new JFrame("JFrame");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
JButton button = new JButton("Open JDialog With JFXPanel");
button.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent event) {
System.err.println("Opening JFXPanel");
JDialog dialog = new JDialog(frame, "JDialog");
final JFXPanel fxPanel = new JFXPanel();
dialog.setModal(true);
dialog.setModalityType(ModalityType.APPLICATION_MODAL);
dialog.add(fxPanel);
Platform.setImplicitExit(false);
Platform.runLater(new Runnable() {
@Override
public void run() {
initFX(fxPanel);
}
private void initFX(JFXPanel fxPanel) {
Button btn = new Button("Open JavaFX Alert");
btn.setOnAction(new EventHandler<javafx.event.ActionEvent>() {
@Override
public void handle(javafx.event.ActionEvent t) {
System.err.println("Javafx button pressed");
Alert alert = new Alert(AlertType.INFORMATION);
alert.setTitle("Javafx Alert");
alert.setHeaderText("Look, an Information Dialog");
alert.setContentText("I have a great message for you!");
alert.initModality(Modality.APPLICATION_MODAL);
Field f;
try {
f = JFXPanel.class.getDeclaredField("stage");
f.setAccessible(true);
alert.initOwner((Window) f.get(fxPanel));
} catch (NoSuchFieldException ex) {
Logger.getLogger(TestFXInSwing.class.getName()).log(Level.SEVERE, null, ex);
} catch (SecurityException ex) {
Logger.getLogger(TestFXInSwing.class.getName()).log(Level.SEVERE, null, ex);
} catch (IllegalArgumentException ex) {
Logger.getLogger(TestFXInSwing.class.getName()).log(Level.SEVERE, null, ex);
} catch (IllegalAccessException ex) {
Logger.getLogger(TestFXInSwing.class.getName()).log(Level.SEVERE, null, ex);
}
alert.showAndWait();
}
});
StackPane root = new StackPane();
root.getChildren().add(btn);
Scene scene = new Scene(root, 500, 500);
fxPanel.setScene(scene);
}
});
dialog.setVisible(true);
}
});
frame.getContentPane().add(button);
//Display the window.
frame.pack();
frame.setVisible(true);
}
public static void main(String[] args) {
javax.swing.SwingUtilities.invokeLater(new Runnable() {
public void run() {
createAndShowGUI();
}
});
}
}