JavaFX - 阻止用户在不使用 MODAL 的情况下更改阶段

标签 java javafx

我有一个如下所示的应用程序:

enter image description here

当用户单击这副牌时,它会打开一个新的舞台。

可以通过以下两种方式之一关闭此阶段:

  • 右键单击舞台。

  • 在舞台外部单击(当失去焦点时它有一个事件处理程序)。

但是,有时我需要用户使用此窗口从牌堆中选择一张或多张牌。在他选择至少一张牌之前,我不想让他关闭窗口。这意味着我必须使用 MODAL 来阻止他访问下面的舞台(我的应用程序)。 MODAL 的问题是现在他永远无法像以前那样通过在舞台外单击来离开窗口,即使我希望他能够这样做。他现在只能通过右键离开。我可以添加一个按钮,但我真的不愿意。

我希望我能很好地解释我的问题。你们会建议我做什么?有没有办法可以在没有 MODAL 的情况下以某种方式阻止用户返回上一阶段?在舞台显示后,我也无法更改Modality,因此这不起作用。

谢谢!

最佳答案

这个想法是使用 onCloseRequestProperty弹出 Stage 的属性。

Called when there is an external request to close this Window. The installed event handler can prevent window closing by consuming the received event.

使用此属性,如果不满足条件(在您的情况下至少选择一张卡),您可以通过调用 consume 来中断 Stage 的关闭。在 WindowEvent 上。

注意:正如文档所述:仅当请求是外部时才有效,因此如果您调用 close Stage 的方法,附加的监听器将不会被执行。作为解决方案,您可以触发 WindowEvent.WINDOW_CLOSE_REQUEST 而不是调用此方法。手动事件。

示例:

public class PopUpApp extends Application {

    Stage popupStage;
    Stage primaryStage;

    @Override
    public void start(Stage stage) {
        try {
            BorderPane root = new BorderPane();
            Scene scene = new Scene(root, 400, 400);
            primaryStage = stage;

            initPopUpStage();

            // When the Pop-Up stage is showing, do not handle any action on the
            // main GUI
            root.disableProperty().bind(popupStage.showingProperty());

            Button b = new Button("Open deck");
            b.setOnAction(new EventHandler<ActionEvent>() {

                @Override
                public void handle(ActionEvent event) {

                    // Add some ToggleButtons to simulate the cards
                    VBox vbox = new VBox();
                    vbox.setAlignment(Pos.CENTER);

                    List<ToggleButton> toggles = new ArrayList<ToggleButton>();

                    for (int i = 0; i < 4; i++) {
                        ToggleButton tb = new ToggleButton("Card " + i + 1);
                        toggles.add(tb);
                    }
                    vbox.getChildren().addAll(toggles);

                    Scene sc = new Scene(vbox, 300, 300);
                    popupStage.setScene(sc);

                    // On close request check for the condition
                    popupStage.setOnCloseRequest(new EventHandler<WindowEvent>() {

                        @Override
                        public void handle(WindowEvent event) {
                            Boolean readytoClose = false;
                            for (ToggleButton toggle : toggles) {
                                if (toggle.isSelected()) {
                                    readytoClose = true;
                                    break;
                                }
                            }

                            // Consume the event a show a dialog
                            if (!readytoClose) {
                                event.consume();
                                Alert alert = new Alert(AlertType.INFORMATION,
                                        "At least one card has be to be selected!");
                                alert.showAndWait();
                            }
                        }
                    });

                    popupStage.show();

                }
            });

            root.setCenter(b);

            primaryStage.setScene(scene);
            primaryStage.show();
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    private void initPopUpStage() {
        popupStage = new Stage();
        popupStage.initOwner(primaryStage);
        popupStage.initStyle(StageStyle.UNDECORATED);
        // On focus loss, close the window
        popupStage.focusedProperty().addListener(new ChangeListener<Boolean>() {

            @Override
            public void changed(ObservableValue<? extends Boolean> observable, Boolean oldValue, Boolean newValue) {

                // Rather than popupStage.close(); fire the event manually
                if (!newValue)
                    popupStage.fireEvent(new WindowEvent(popupStage, WindowEvent.WINDOW_CLOSE_REQUEST));
            }
        });
    }

    public static void main(String[] args) {
        launch(args);
    }
}

更新:

为了使主Stage不可用,我添加了这一行:

root.disableProperty().bind(popupStage.showingProperty());

这将在显示弹出阶段时禁用根 BorderPane。弹出窗口关闭后,主窗口将再次启用。

关于JavaFX - 阻止用户在不使用 MODAL 的情况下更改阶段,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/37824263/

相关文章:

java - 程序输出中的间距错误

java - CodenameOne:将智能手机/平板电脑应用程序转换为 Linux 桌面应用程序

JavaFx:TableView 足够还是我需要自定义 Controller

java - 将程序输出附加到 JavaFX TextBox

java - 将带有 FloatProperty 的 ObjectProperty 绑定(bind)到其他属性

java - 在 android 中启用静音模式而不触发请勿打扰

java - 为什么Java中的属性可以公开?

css - 如何在 JavaFX 的 tabPane 中删除这个额外的空间?

javafx - 实现拖动多个选中的节点

java - 有没有办法在没有证书的情况下进行 JNLP?