阻止程序执行直到用户单击按钮

时间:2014-04-16 22:50:42

标签: java user-interface javafx

我正在尝试制作类似于Swing的{​​{1}}的模态对话框。我想提出一个确认对话框,在我在代码中执行某些操作之前,该对话框会让用户明确地说“是”。

我从:https://gist.github.com/jewelsea/1887631

无耻地偷走了这个例子

并将其修改为:

JOptionPane

我的问题是,当弹出此对话框时,即使用户没有选择选项(是或否),程序也会继续执行。

我已经尝试设置一个布尔值并在循环中检查它以知道何时应该检查用户选择,但这最终会导致其他程序(竞争条件和/或阻止包括对话框在内的所有内容)。

public class ModalConfirmDialog {
    private boolean confirm = false;
    private boolean isDialogOpen = false;

    public boolean isOpen() {
        return isDialogOpen;
    }

    public boolean getConfirmation() {
        return confirm;
    }

    public void showConfirmationDialog(final Stage primaryStage) {
        // initialize the confirmation dialog
        final Stage dialog = new Stage(StageStyle.TRANSPARENT);
        dialog.initModality(Modality.WINDOW_MODAL);
        dialog.initOwner(primaryStage);
        dialog.setScene(
                new Scene(
                        HBoxBuilder.create().styleClass("modal-dialog").children(
                                LabelBuilder.create().text("Confirm Action?").build(),
                                ButtonBuilder.create().text("Yes").defaultButton(true).onAction(new EventHandler<ActionEvent>() {
                                    @Override public void handle(ActionEvent actionEvent) {
                                        // take action and close the dialog.
                                        primaryStage.getScene().getRoot().setEffect(null);
                                        dialog.close();
                                        confirm = true;
                                        isDialogOpen = false;
                                    }
                                }).build(),
                                ButtonBuilder.create().text("No").cancelButton(true).onAction(new EventHandler<ActionEvent>() {
                                    @Override public void handle(ActionEvent actionEvent) {
                                        // abort action and close the dialog.
                                        primaryStage.getScene().getRoot().setEffect(null);
                                        dialog.close();
                                        confirm = false;
                                        isDialogOpen = false;
                                    }
                                }).build()
                                ).build()
                                , Color.TRANSPARENT
                        )
                );
        dialog.getScene().getStylesheets().add(getClass().getResource("modal-dialog.css").toExternalForm());

        // allow the dialog to be dragged around.
        final Node root = dialog.getScene().getRoot();
        final Delta dragDelta = new Delta();
        root.setOnMousePressed(new EventHandler<MouseEvent>() {
            @Override public void handle(MouseEvent mouseEvent) {
                // record a delta distance for the drag and drop operation.
                dragDelta.x = dialog.getX() - mouseEvent.getScreenX();
                dragDelta.y = dialog.getY() - mouseEvent.getScreenY();
            }
        });
        root.setOnMouseDragged(new EventHandler<MouseEvent>() {
            @Override public void handle(MouseEvent mouseEvent) {
                dialog.setX(mouseEvent.getScreenX() + dragDelta.x);
                dialog.setY(mouseEvent.getScreenY() + dragDelta.y);
            }
        });
        primaryStage.getScene().getRoot().setEffect(new BoxBlur());
        dialog.show();
        isDialogOpen = true;
    }

    //records relative x and y co-ordinates.
    class Delta { double x, y; }
}

我不确定如何在没有需要将 ModalConfirmDialog dialog = new ModalConfirmDialog(); dialog.showConfirmationDialog((Stage) relatedTransTable.getScene().getWindow()); while (dialog.isOpen()) { // wait for it to close? } if (dialog.getConfirmation()) { System.out.println("Confirmed choice!"); } else { System.out.println("User denied choice!"); } 嵌入到我的完整JOptionPane应用程序中的情况下复制Swing

2 个答案:

答案 0 :(得分:7)

<强>解决方案

使用showAndWait显示对话框。

  

显示此阶段并在返回调用者之前等待隐藏(关闭)它。此方法临时阻止当前事件的处理,并启动嵌套事件循环以处理其他事件。


  

我试图创建一个类似于Swing的JOptionPane的模态对话框。

Java 8u40中的javafx.scene.control.Alert类提供类似于Swing的JOptionPane的功能,其设计和实现受到JOptionPane的严重影响。


当前推荐

  1. 对于警报或确认等基本常用对话框,请使用JavaFX 8u40 +工具包中的内置对话框功能。 Early access release for 8u40可用,对话框API稳定,将映射到预计的2015年3月产品发布。
  2. 如果您需要特定类型的对话框,例如登录,字体选择,进度反馈和向导等任务,请使用ControlsFX(支持更大的范围)默认对话框实现,而不是核心JavaFX平台。)

  3. 如果您需要完全自定义的对话,请使用本答案后面列出的技术。

  4. <强>背景

    不要重新发明轮子。将ControlsFX库用于JOptionPane类型对话框,而不是编写自己的实现(而JavaFX 8u40将introduce common dialog boxes into the platform)。

    您为模态对话框显示引用的代码现在已经很老了。在JavaFX核心平台和第三方库中实现了许多功能(包括添加showAndWait),这意味着如果你今天正在完成任务,它可能会以不同的方式完成。

    问题中引用的代码使用了在Java 8中已弃用的构建器,因此不再建议使用它们(它们甚至不再显示在JavaFX javadoc中)。

    代码演示内置JavaFX 8u40 +警报类

    import javafx.application.Application;
    import javafx.scene.Scene;
    import javafx.scene.control.*;
    import javafx.stage.Stage;
    
    public class ShowAndWaitBuiltInAlert extends Application {
        @Override public void start(Stage stage) {
            Button showDialog = new Button("Show Dialog");
            showDialog.setOnAction(event -> {
                Alert dialog = new Alert(
                        Alert.AlertType.CONFIRMATION,
                        "Are you sure you want to exit the Dialog Demo Application?"
                );
                dialog.showAndWait()
                        .filter(response -> response.equals(ButtonType.OK))
                        .ifPresent(response -> stage.close());
            });
    
            stage.setScene(new Scene(showDialog));
            stage.show();
        }
    
        public static void main(String[] args) { launch(args); }
    }
    

    警报从Dialog扩展,因此可以使用Dialog类的所有自定义方法进行自定义。

    代码演示内置JavaFX 8u40 + Dialog类

    confirm dialog same

    import javafx.application.Application;
    import javafx.scene.Scene;
    import javafx.scene.control.*;
    import javafx.stage.Stage;
    
    public class ShowAndWaitBuiltInDialog extends Application {    
        @Override public void start(Stage stage) {
            Button showDialog = new Button("Show Dialog");
            showDialog.setOnAction(e -> {
                Dialog<ButtonType> dialog = new Dialog<>();
                dialog.setTitle("Dialog Demo");
                dialog.setHeaderText("Confirm Exit");
                dialog.setContentText("Are you sure you want to exit the Dialog Demo Application?");
                ButtonType exit = new ButtonType("Exit", ButtonBar.ButtonData.OK_DONE);
                dialog.getDialogPane().getButtonTypes().addAll(
                        exit, ButtonType.CANCEL
                );
                dialog.showAndWait()
                        .filter(response -> response.equals(exit))
                        .ifPresent(response -> stage.close());
            });
    
            stage.setScene(new Scene(showDialog));
            stage.show();
        }
    
        public static void main(String[] args) { launch(args); }
    }
    

    自定义对话框代码演示showAndWait

    以下代码适用于早于Java 8u40的Java 8版本。

    dialogsample

    import javafx.application.Application;
    import javafx.beans.property.*;
    import javafx.geometry.*;
    import javafx.scene.Scene;
    import javafx.scene.control.*;
    import javafx.scene.layout.*;
    import javafx.stage.*;
    
    public class ShowAndWaitDialog extends Application {
    
        public static void main(String[] args) {
            launch(args);
        }
    
        @Override
        public void start(Stage stage) {
            Button showDialog = new Button("Show Dialog");
            showDialog.setOnAction(e -> {
                ConfirmationDialog dialog = new ConfirmationDialog(
                        "Would you like to exit the application?"
                );
                dialog.setY(stage.getY() + stage.getHeight() + 10);
                dialog.setX(stage.getX());
                dialog.showAndWait();
                if (dialog.isSelected()) {
                    stage.close();
                }
            });
            stage.setScene(new Scene(showDialog));
            stage.show();
        }
    
        class ConfirmationDialog extends Stage {
            private VBox layout = new VBox();
    
            private ReadOnlyBooleanWrapper selected = new ReadOnlyBooleanWrapper();
            public boolean isSelected() {
                return selected.get();
            }
            public ReadOnlyBooleanProperty selectedProperty() {
                return selected.getReadOnlyProperty();
            }
    
            public ConfirmationDialog(String question) {
                initStyle(StageStyle.UTILITY);
                initModality(Modality.APPLICATION_MODAL);
    
                layout.setSpacing(10);
                layout.setPadding(new Insets(10));
    
                createControls();
    
                layout.getChildren().addAll(
                        new Label(question),
                        createControls()
                );
    
                setScene(new Scene(layout));
                sizeToScene();  // workaround because utility stages aren't automatically sized correctly to their scene.
            }
    
            private HBox createControls() {
                final Button ok = new Button("OK");
                ok.setOnAction(e -> {
                    selected.set(true);
                    close();
                });
    
                final Button cancel = new Button("Cancel");
                cancel.setOnAction(e -> {
                    selected.set(false);
                    close();
                });
    
                final HBox controls = new HBox(10, ok, cancel);
                controls.setAlignment(Pos.CENTER_RIGHT);
    
                return controls;
            }
        }
    }
    

    2014年12月19日评论问题更新

      

    这不是每个UI框架中预期的一些基本UI功能吗?为什么到目前为止JavaFX缺少这种原生功能?

    showAndWait已经在JavaFX中使用了大约两年半,并且在JavaFX 2发布之后大约8个月添加,直到showAndWait在JavaFX 2.2中作为公共API出现。在此期间,showAndWait功能的大部分可以使用类似于提问者问题中的代码的事件处理程序进行模拟。

    在内置通用对话框API的更一般情况下,例如警报和确认(现已添加到Java 8u40),JavaFX问题跟踪器中为该功能提供了大量的历史记录,设计讨论和初始延迟原因RT-12643

答案 1 :(得分:0)

dialog.setModal(true);
dialog.add(stuff here);
dialog.setVisible(true);

如果我正确地阅读了您的问题,那么上面的代码会使对话框像joptionpane&amp; amp;在对话框打开时阻止用户点击除对话框之外的任何内容