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

标签 java user-interface javafx

我正在尝试创建一个类似于 SwingJOptionPane 的模态对话框。我想呈现一个确认对话框,让用户在我在代码中执行某些操作之前明确地说"is"。

我无耻地从以下位置窃取了这个示例:https://gist.github.com/jewelsea/1887631

并将其修改为:

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

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

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

    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 嵌入到我的整个 JavaFX 应用程序中。

最佳答案

解决方案

使用showAndWait显示您的对话框。

Shows this stage and waits for it to be hidden (closed) before returning to the caller. This method temporarily blocks processing of the current event, and starts a nested event loop to handle other events.


I'm attempting to make a modal dialog similar to Swing's 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. 如果您需要一个完全自定义的对话框,请使用本答案后面概述的技术。

背景

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

您为模态对话框显示引用的代码现在已经很旧了。在 JavaFX 核心平台和第 3 方库中实现了许多功能(包括添加的 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+ 对话框类

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 日评论问题更新

Isn't this some basic UI functionality expected in every UI framework? Why did JavaFX lacked this native functionality until now?

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

在更一般的情况下,内置通用对话框 API 用于警告和确认(现已添加到 Java 8u40),JavaFX 问题跟踪器中提供了广泛的历史、设计讨论和初始延迟原因RT-12643 .

关于java - 阻止程序执行,直到用户单击按钮,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/23121580/

相关文章:

java - Arraylist 构造函数不创建新对象引用

java - 如何将值绑定(bind)到 ObservableList 的大小?

java - Thymeleaf 3 URL 解析不适​​用于 Spring Boot 4 + Spring Security

Java:从磁盘写入/读取 map

python - 如何将选择(点击)写入文件

java - 为 2 版本的数据模式设计 Web 界面

JavaFX检测同时按下的多个键盘按键

java - javafx2中的可编辑表

java - 如何使用 RxJava 2 的 CompositeDisposable?

c# - 如何从业务层更新UI?