在Swing应用程序中制作JavaFX警报/对话框模态

时间:2015-01-21 01:28:57

标签: swing javafx modal-dialog alert jdesktoppane

因此,我们再次将使用完全Swing的现有Java应用程序转换为使用JavaFX。但是,该应用程序将不会完全使用JavaFX。这似乎导致了警报/对话和模态的一些问题。我们目前正在使用Java 8u40。

主应用程序基本上是一个带有菜单的JFrame。主内容窗格是JDesktopPane,单击MenuItem会在DeskopPane中打开新的JInternalFrame。我们转换为JavaFX的屏幕目前基本上是JInternalFrame中的JFXPanel。从JFXPanel打开的任何警报/对话框都是面板本身的模态,但不是JInternalFrame,DeskopPane,Menu等。

我在DialogPane文档中读到他们计划在JavaFX的未来版本中引入一些轻量级对话框甚至可能是InternalFrames,所以我们可能只需要等待一段时间才能实现这一功能。但是,理想情况下,当打开一个新的警报/对话框时,它将是整个应用程序的模态。

编辑: 目前正在对模态对话框执行以下操作:

((Stage)getDialogPane().getScene().getWindow()).setAlwaysOnTop(true);

这使对话框始终显示在顶部,但即使我们的主应用程序已最小化,对话框也会保留在其他应用程序之上。它也不会阻止对帧中任何Swing组件的输入。

3 个答案:

答案 0 :(得分:2)

我认为我完全理解你的问题。但这是我的猜测 - 您正在尝试从某些JFXPanel创建一个警告窗口,该窗口将是模态的(即,用户将无法在您的应用程序中单击,直到她关闭该警报窗口)到您的整个应用程序,这是部分使用摆动组件书写。

如果您的应用程序是用纯JavaFX编写的,那么您可以执行类似的操作(假设您已在JFXPanel中的某处创建了一个按钮)

button.setOnAction(evt -> {
    Alert alert = new Alert(Alert.AlertType.INFORMATION);
    alert.initModality(Modality.APPLICATION_MODAL);

    // This will not work in your code
    alert.initOwner(button.getScene().getWindow());

    alert.show();
});

但由于initOwner要求传递swing组件的javafx.stage.window对象在您的代码中不起作用。从Java 8u40开始,我认为没有正确的方法(即不是黑客)将Alert个对象的所有权设置为swing组件。毫不奇怪,这些问题已被提出here,并且在写这篇文章时没有回答。

根据您的要求,您可以使用JOptionPane.showMessageDialog方法及其外观作为解决方法。

button.setOnAction(evt -> {
    JOptionPane.showMessageDialog(desktopPane,"My message");
});

默认情况下,这些对话框是模态的,因此无需任何工作。您可以从JavaFX组件的任何事件处理程序方法中调用它们。

答案 1 :(得分:1)

我已经使用JavaFXFrame中实现的小界面做了一些解决方法:

public interface DialogParent {
    void setOnFocusGained(EventHandler<FocusEvent> focusHandler);
    void setOnCloseRequest(EventHandler<WindowEvent> closeHandler);
}

还有我的JavaFXFrame实现

public class JavaFXFrame implements DialogParent {
    private JFrame frame;
    private EventHandler<ch.irix.sumadmin.util.FocusEvent> focusGainedHandler;
    private EventHandler<javafx.stage.WindowEvent> windowClosingHandler;

public void JavaFXFrame() {
    final JFXPanel fxPanel = new JFXPanel();
    frame = new JFrame();
    frame.add(fxPanel);
    frame.addWindowListener(new WindowAdapter() {
        @Override
        public void windowClosing(WindowEvent e) {
            tryClosing(this);
        }
    });
    frame.addWindowFocusListener(new WindowAdapter() {
        @Override
        public void windowGainedFocus(WindowEvent e) {
            if (focusGainedHandler != null) {
                focusGainedHandler.handle(new FocusEvent());
            }
        }
    });
}

public void setVisible(boolean visible) {
    frame.setVisible(visible);
}

private void tryClosing(WindowListener listener) {
    javafx.stage.WindowEvent windowEvent = new javafx.stage.WindowEvent(null,    javafx.stage.WindowEvent.WINDOW_CLOSE_REQUEST);
    if (windowClosingHandler != null) {
        windowClosingHandler.handle(windowEvent);
    }
    if (!windowEvent.isConsumed()) {
        frame.setVisible(false);
    }
}

@Override
public void setOnFocusGained(EventHandler<ch.irix.sumadmin.util.FocusEvent> focusGainedHandler) {
    this.focusGainedHandler = focusGainedHandler;
}

@Override
public void setOnCloseRequest(EventHandler<javafx.stage.WindowEvent> windowClosingHandler) {
    this.windowClosingHandler = windowClosingHandler;
}

}

并显示警报:

public static void showAlert(Alert alert) {
    DialogPane dialogPane = alert.getDialogPane();
    final Stage stage = new Stage();
    stage.setScene(dialogPane.getScene());
    List<ButtonType> buttonTypes = dialogPane.getButtonTypes();
    for (ButtonType buttonType : buttonTypes) {
        ButtonBase button = (ButtonBase) dialogPane.lookupButton(buttonType);
        button.setOnAction(evt -> {
            dialogPane.setUserData(buttonType);
            stage.close();
        });
    }
    dialogParent.setOnFocusGained(event -> {
        stage.toFront();
    });
    dialogParent.setOnCloseRequest(Event::consume);
    stage.setOnCloseRequest(event -> {
        dialogParent.setOnFocusGained(null);
        dialogParent.setOnCloseRequest(null);
    });
    stage.show();
}

希望这对您有帮助

答案 2 :(得分:1)

您可以使用以下变通办法,在显示JDialog时创建一个不可见的Alert,并在JDialog关闭时放置Alert。这种方法将模式扩展到整个应用程序,包括Swing部分。

// create Alert
Alert alert = new Alert(AlertType.INFORMATION, "Hello");

// create invisible JDialog and "show" it
JDialog dialog = new JDialog();
dialog.setModal(true);
dialog.setUndecorated(true);
dialog.setDefaultCloseOperation(JFrame.DO_NOTHING_ON_CLOSE);
SwingUtilities.invokeLater(() -> dialog.setVisible(true));

// show Alert
alert.showAndWait();

// close JDialog after Alert is closed
dialog.dispose();