简体   繁体   English

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

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

So once again we are in the process of converting our existing Java application that was using entirely Swing to using JavaFX.因此,我们再次将完全使用 Swing 的现有 Java 应用程序转换为使用 JavaFX。 However, the application will not be using JavaFX entirely.但是,该应用程序不会完全使用 JavaFX。 This seems to be causing some issues with Alerts/Dialogs and modality.这似乎会导致警报/对话框和模式出现一些问题。 We are currently using Java 8u40.我们目前使用的是 Java 8u40。

The main application is basically in a JFrame that has a Menu.主应用程序基本上位于具有菜单的 JFrame 中。 The main content pane is JDesktopPane and clicking a MenuItem opens new JInternalFrames within the DeskopPane.主要内容窗格是 JDesktopPane,单击 MenuItem 会在 DeskopPane 中打开新的 JInternalFrames。 Screens we are converting to JavaFX are basically JFXPanels within a JInternalFrame at the moment.目前,我们正在转换为 JavaFX 的屏幕基本上是 JInternalFrame 中的 JFXPanel。 Any Alerts/Dialogs that are opened from the JFXPanels are modal to the panel itself, but not to the JInternalFrame, DeskopPane, Menu, etc.从 JFXPanel 打开的任何警报/对话框都是面板本身的模式,但不是 JInternalFrame、DeskopPane、Menu 等。

I read in the DialogPane documentation that they are planning to introduce some lightweight dialogs and even possibly InternalFrames in future releases of JavaFX, so maybe we'll just have to wait it out a little longer for this functionality.我在 DialogPane 文档中读到,他们计划在 JavaFX 的未来版本中引入一些轻量级对话框,甚至可能引入 InternalFrames,所以也许我们只需要再等一段时间才能使用此功能。 But, ideally when opening a new Alert/Dialog it would be modal to the entire Application.但是,理想情况下,当打开一个新的警报/对话框时,它将是整个应用程序的模态。

EDIT: Currently doing the following for modal dialogs:编辑:目前正在为模态对话框执行以下操作:

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

This makes the dialog always appear on top, however the dialog also remains on top of other applications even if our main application is minimized.这使得对话框始终显示在顶部,但是即使我们的主应用程序被最小化,该对话框也会保留在其他应用程序的顶部。 It also does not block input to any Swing components in the frame.它也不会阻止输入到框架中的任何 Swing 组件。

You can use the following work-around which creates an invisible JDialog when the Alert is shown and disposes the JDialog when the Alert is closed.您可以使用以下解决方法,在显示Alert时创建一个不可见的JDialog ,并在Alert关闭时处理JDialog This approach extends the modality to the whole application, including the Swing part.这种方法将模态扩展到整个应用程序,包括 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();

I don't think i understand your question completely.我不认为我完全理解你的问题。 But here is my guess - You are trying to make an alert window from some JFXPanel that will be modal (ie user will not be able to click in your application until she closes that alert window) to your entire application which is written partially using swing components.但这是我的猜测 - 您正在尝试从一些JFXPanel中创建一个警报窗口,该窗口将是模态的(即用户在关闭该警报窗口之前将无法单击您的应用程序)到您的整个应用程序,该应用程序部分使用 swing成分。

If your application would be written in purely JavaFX then you would do something like (Assuming you have created a button somewhere in your 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();
});

but since initOwner requires a javafx.stage.window object passing a swing component won't work in your code.但由于initOwner需要一个javafx.stage.window对象,传递一个 Swing 组件在您的代码中不起作用。 As of Java 8u40 i don't think there is a right way(ie not hacks) to set ownership of Alert objects to swing component.从 Java 8u40 开始,我认为没有正确的方法(即不是黑客)将Alert对象的所有权设置为摆动组件。 Not surprisingly such questions has already been asked here and not answered as of writing this.毫不奇怪,这里已经提出这样的问题,但在撰写本文时尚未回答。

For your requirements you can use JOptionPane.showMessageDialog method and its look alike as workaround.对于您的要求,您可以使用JOptionPane.showMessageDialog方法及其外观作为解决方法。

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

These dialog boxes are modal by default so no work is necessary.默认情况下,这些对话框是模态的,因此无需进行任何操作。 You can call these from any event handler methods of JavaFX components.您可以从 JavaFX 组件的任何事件处理程序方法调用这些。

I've done a little workaround with a small interface which is implemented in my JavaFXFrame:我已经使用在我的 JavaFXFrame 中实现的小接口做了一些解决方法:

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

And my JavaFXFrame implementation还有我的 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;
}

} }

And showing an Alert:并显示警报:

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();
}

Hope this will help you希望能帮到你

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

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