簡體   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