繁体   English   中英

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

[英]Making JavaFX Alerts/Dialogs Modal within Swing Application

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

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

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

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

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

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

您可以使用以下解决方法,在显示Alert时创建一个不可见的JDialog ,并在Alert关闭时处理JDialog 这种方法将模态扩展到整个应用程序,包括 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();

我不认为我完全理解你的问题。 但这是我的猜测 - 您正在尝试从一些JFXPanel中创建一个警报窗口,该窗口将是模态的(即用户在关闭该警报窗口之前将无法单击您的应用程序)到您的整个应用程序,该应用程序部分使用 swing成分。

如果您的应用程序将纯粹用 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需要一个javafx.stage.window对象,传递一个 Swing 组件在您的代码中不起作用。 从 Java 8u40 开始,我认为没有正确的方法(即不是黑客)将Alert对象的所有权设置为摆动组件。 毫不奇怪,这里已经提出这样的问题,但在撰写本文时尚未回答。

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

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

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

我已经使用在我的 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();
}

希望能帮到你

暂无
暂无

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

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