【问题标题】:Problems with JavaFX dialogJavaFX 对话框的问题
【发布时间】:2017-10-05 06:52:03
【问题描述】:

我有一个带有主窗口的 JavaFX 应用程序。单击“创建用户”按钮后,将显示一个对话框以获取用户的输入。单击对话框上的“确定”按钮后,对话框被禁用,光标变为等待,而应用程序执行必要的任务来创建新用户。如果任务成功,对话框将关闭,并显示信息警报以宣布成功。

以下是我从实际代码中简化的代码,以重现我遇到的问题。以下是问题:

  1. 为什么 dialog.getDialogPane().setCursor(Cursor.WAIT) 不起作用?我可以使用 primaryStage.getScene().setCursor(Cursor.WAIT) 更改主窗口上的光标。但是如何更改对话框上的光标?

  2. 显示警报时,即使在显示警报之前调用了 dialog.close(),似乎对话框也可能不会关闭(但是,如果我只用一个按钮和没有别的,当我调用 dialog.close()) 时它会消失。此外,当我拖动警报框时,对话框及其后面的主窗口不会刷新。所以看起来代码有问题。

代码:

import javafx.application.Application;
import javafx.concurrent.Task;
import javafx.event.ActionEvent;
import javafx.geometry.Insets;
import javafx.geometry.Pos;
import javafx.scene.Cursor;
import javafx.scene.Scene;
import javafx.scene.control.Alert;
import javafx.scene.control.Button;
import javafx.scene.control.ButtonType;
import javafx.scene.control.Dialog;
import javafx.scene.control.Label;
import javafx.scene.control.PasswordField;
import javafx.scene.control.TableColumn;
import javafx.scene.control.TableView;
import javafx.scene.control.TextField;
import javafx.scene.control.Alert.AlertType;
import javafx.scene.layout.GridPane;
import javafx.scene.layout.VBox;
import javafx.scene.text.Text;
import javafx.stage.Stage;

public class Demo extends Application {

    private Dialog<String> dialog;
    private Button createUserButton = new Button("Create User");

    @Override
    public void start(Stage primaryStage) throws Exception {
        Text usersLabel = new Text("Current Users:");
        TableColumn<User, String> indexColumn = new TableColumn<User, String>("No.");
        indexColumn.setMaxWidth(1f * Integer.MAX_VALUE * 10);
        indexColumn.setCellValueFactory(p -> p.getValue().indexProperty());
        TableColumn<User, String> userNameColumn = new TableColumn<User, String>("User Name");
        userNameColumn.setMaxWidth(1f * Integer.MAX_VALUE * 60);
        userNameColumn.setCellValueFactory(p -> p.getValue().userNameProperty());
        TableColumn<User, String> roleColumn = new TableColumn<User, String>("Role");
        roleColumn.setMaxWidth(1f * Integer.MAX_VALUE * 30);
        roleColumn.setCellValueFactory(p -> p.getValue().roleProperty());
        TableView<User> tableView = new TableView<User>();
        tableView.getColumns().add(indexColumn);
        tableView.getColumns().add(userNameColumn);
        tableView.getColumns().add(roleColumn);
        tableView.setColumnResizePolicy(TableView.CONSTRAINED_RESIZE_POLICY);
        Text dummyLabel = new Text("");
        createUserButton.setOnAction(event -> showDialog());
        VBox leftPane = new VBox(5);
        leftPane.getChildren().addAll(usersLabel, tableView);
        VBox rightPane = new VBox(20);
        rightPane.setFillWidth(true);
        rightPane.getChildren().addAll(dummyLabel, createUserButton);
        GridPane mainPane = new GridPane();
        mainPane.setPadding(new Insets(10, 0, 0, 10));
        mainPane.setHgap(20);
        mainPane.add(leftPane, 0, 0);
        mainPane.add(rightPane, 1, 0);
        Scene scene = new Scene(mainPane);
        primaryStage.setScene(scene);
        primaryStage.setResizable(false);
        primaryStage.show();
    }

    private void showDialog() {
        dialog = new Dialog<>();
        dialog.setTitle("Create User");
        dialog.setHeaderText("Please enter User Name and Password to create a new user.");
        dialog.setResizable(false);
        Label userNameLabel = new Label("User Name:");
        Label passwordLabel = new Label("Password:");
        TextField userNameField = new TextField();
        PasswordField passwordField = new PasswordField();
        GridPane grid = new GridPane();
        grid.setAlignment(Pos.CENTER);
        grid.setHgap(10);
        grid.setVgap(10);
        grid.setPadding(new Insets(20, 35, 20, 35));
        grid.add(userNameLabel, 1, 1);
        grid.add(userNameField, 2, 1);
        grid.add(passwordLabel, 1, 2);
        grid.add(passwordField, 2, 2);
        dialog.getDialogPane().setContent(grid);
        dialog.getDialogPane().getButtonTypes().add(ButtonType.OK);
        Button okButton = (Button) dialog.getDialogPane().lookupButton(ButtonType.OK);
        okButton.addEventFilter(ActionEvent.ACTION, event -> {
            createUser(userNameField.getText().trim(), passwordField.getText());
            event.consume();
        });
        dialog.getDialogPane().getButtonTypes().add(ButtonType.CANCEL);
        dialog.showAndWait();
    }

    private void createUser(String userName, String password) {
        dialog.getDialogPane().setDisable(true);
        dialog.getDialogPane().setCursor(Cursor.WAIT); // does not work!
        Task<Boolean> task = new Task<Boolean>() {
            @Override
            public Boolean call() {
                try {
                    Thread.sleep(2000); // simulate processing
                } catch (InterruptedException exception) {
                }
                return Boolean.TRUE;
            }
        };
        task.setOnSucceeded(e -> {
            Boolean success = task.getValue();
            dialog.getDialogPane().setDisable(false);
            dialog.getDialogPane().setCursor(Cursor.DEFAULT);
            if (success.booleanValue()) {
                dialog.close(); // does not seem to close before alert is shown
                Alert alert = new Alert(AlertType.INFORMATION);
                alert.setTitle("Create User Successful");
                alert.setHeaderText("The user is successfully created.");
                alert.showAndWait();
            } else {
                Alert alert = new Alert(AlertType.ERROR);
                alert.setTitle("Create User Error");
                alert.setHeaderText("Unable to create user.");
                alert.showAndWait();
            }
        });
        new Thread(task).start();
    }

    public static void main(String[] arguments) {
        Application.launch(arguments);
    }

}

下面是 User 类的代码:

import javafx.beans.property.SimpleStringProperty;
import javafx.beans.property.StringProperty;

public class User {

    private StringProperty index;

    private StringProperty userName;

    private StringProperty role;

    public void setIndex(String index) {
        indexProperty().set(index);
    }

    public String getIndex() {
        return indexProperty().get();
    }

    public StringProperty indexProperty() {
        if (index == null) {
            index = new SimpleStringProperty(this, "index");
        }
        return index;
    }

    public void setUserName(String userName) {
        userNameProperty().set(userName);
    }

    public String getUserName() {
        return userNameProperty().get();
    }

    public StringProperty userNameProperty() {
        if (userName == null) {
            userName = new SimpleStringProperty(this, "userName");
        }
        return userName;
    }

    public void setRole(String role) {
        roleProperty().set(role);
    }

    public String getRole() {
        return roleProperty().get();
    }

    public StringProperty roleProperty() {
        if (role == null) {
            role = new SimpleStringProperty(this, "role");
        }
        return role;
    }

}

编辑:

(1) 对于光标问题,我只需要更改这一行:

dialog.getDialogPane().setCursor(Cursor.WAIT);

到:

dialog.getDialogPane().getScene().setCursor(Cursor.WAIT)

(2)对于第二个问题,我只需要更改这一行:

dialog.close();

到:

Platform.runLater(() -> {
    dialog.close();
});

解决方案:

import javafx.application.Application;
import javafx.application.Platform;
import javafx.concurrent.Task;
import javafx.event.ActionEvent;
import javafx.geometry.Insets;
import javafx.geometry.Pos;
import javafx.scene.Cursor;
import javafx.scene.Scene;
import javafx.scene.control.Alert;
import javafx.scene.control.Button;
import javafx.scene.control.ButtonType;
import javafx.scene.control.Dialog;
import javafx.scene.control.Label;
import javafx.scene.control.PasswordField;
import javafx.scene.control.TableColumn;
import javafx.scene.control.TableView;
import javafx.scene.control.TextField;
import javafx.scene.control.Alert.AlertType;
import javafx.scene.layout.GridPane;
import javafx.scene.layout.VBox;
import javafx.scene.text.Text;
import javafx.stage.Stage;

public class Demo extends Application {

    private Dialog<String> dialog;
    private Button createUserButton = new Button("Create User");

    @Override
    public void start(Stage primaryStage) throws Exception {
        Text usersLabel = new Text("Current Users:");
        TableColumn<User, String> indexColumn = new TableColumn<User, String>("No.");
        indexColumn.setMaxWidth(1f * Integer.MAX_VALUE * 10);
        indexColumn.setCellValueFactory(p -> p.getValue().indexProperty());
        TableColumn<User, String> userNameColumn = new TableColumn<User, String>("User Name");
        userNameColumn.setMaxWidth(1f * Integer.MAX_VALUE * 60);
        userNameColumn.setCellValueFactory(p -> p.getValue().userNameProperty());
        TableColumn<User, String> roleColumn = new TableColumn<User, String>("Role");
        roleColumn.setMaxWidth(1f * Integer.MAX_VALUE * 30);
        roleColumn.setCellValueFactory(p -> p.getValue().roleProperty());
        TableView<User> tableView = new TableView<User>();
        tableView.getColumns().add(indexColumn);
        tableView.getColumns().add(userNameColumn);
        tableView.getColumns().add(roleColumn);
        tableView.setColumnResizePolicy(TableView.CONSTRAINED_RESIZE_POLICY);
        Text dummyLabel = new Text("");
        createUserButton.setOnAction(event -> showDialog());
        VBox leftPane = new VBox(5);
        leftPane.getChildren().addAll(usersLabel, tableView);
        VBox rightPane = new VBox(20);
        rightPane.setFillWidth(true);
        rightPane.getChildren().addAll(dummyLabel, createUserButton);
        GridPane mainPane = new GridPane();
        mainPane.setPadding(new Insets(10, 0, 0, 10));
        mainPane.setHgap(20);
        mainPane.add(leftPane, 0, 0);
        mainPane.add(rightPane, 1, 0);
        Scene scene = new Scene(mainPane);
        primaryStage.setScene(scene);
        primaryStage.setResizable(false);
        primaryStage.show();
    }

    private void showDialog() {
        dialog = new Dialog<>();
        dialog.setTitle("Create User");
        dialog.setHeaderText("Please enter User Name and Password to create a new user.");
        dialog.setResizable(false);
        Label userNameLabel = new Label("User Name:");
        Label passwordLabel = new Label("Password:");
        TextField userNameField = new TextField();
        PasswordField passwordField = new PasswordField();
        GridPane grid = new GridPane();
        grid.setAlignment(Pos.CENTER);
        grid.setHgap(10);
        grid.setVgap(10);
        grid.setPadding(new Insets(20, 35, 20, 35));
        grid.add(userNameLabel, 1, 1);
        grid.add(userNameField, 2, 1);
        grid.add(passwordLabel, 1, 2);
        grid.add(passwordField, 2, 2);
        dialog.getDialogPane().setContent(grid);
        dialog.getDialogPane().getButtonTypes().add(ButtonType.OK);
        Button okButton = (Button) dialog.getDialogPane().lookupButton(ButtonType.OK);
        okButton.addEventFilter(ActionEvent.ACTION, event -> {
            createUser(userNameField.getText().trim(), passwordField.getText());
            event.consume();
        });
        dialog.getDialogPane().getButtonTypes().add(ButtonType.CANCEL);
        dialog.showAndWait();
    }

    private void createUser(String userName, String password) {
        dialog.getDialogPane().setDisable(true);
        dialog.getDialogPane().getScene().setCursor(Cursor.WAIT); // Changed
        Task<Boolean> task = new Task<Boolean>() {
            @Override
            public Boolean call() {
                try {
                    Thread.sleep(2000); // simulate processing
                } catch (InterruptedException exception) {
                }
                return Boolean.TRUE;
            }
        };
        task.setOnSucceeded(e -> {
            Boolean success = task.getValue();
            dialog.getDialogPane().setDisable(false);
            dialog.getDialogPane().getScene().setCursor(Cursor.DEFAULT); // Changed
            if (success.booleanValue()) {
                Platform.runLater(() -> { // Added
                    dialog.close();
                });                       // Added
                Alert alert = new Alert(AlertType.INFORMATION);
                alert.setTitle("Create User Successful");
                alert.setHeaderText("The user is successfully created.");
                alert.showAndWait();
            } else {
                Alert alert = new Alert(AlertType.ERROR);
                alert.setTitle("Create User Error");
                alert.setHeaderText("Unable to create user.");
                alert.showAndWait();
            }
        });
        new Thread(task).start();
    }

    public static void main(String[] arguments) {
        Application.launch(arguments);
    }

}

【问题讨论】:

  • 发布您的用户类别。
  • 我刚刚发布了用户类代码。

标签: javafx java-8 javafx-8


【解决方案1】:

您仍然可以禁用DialogPane。但是,我认为通过禁用 DialogPane 您也可以防止它被命中测试,从而无法接收任何鼠标事件。

但是您可以使用DialogPane 的任何父节点(在本例中为场景节点):

dialog.getDialogPane().setDisable(true);
dialog.getDialogPane().getScene().setCursor(Cursor.WAIT);

【讨论】:

  • 谢谢。将 dialog.getDialogPane().setCursor(Cursor.WAIT) 更改为 dialog.getDialogPane().getScene().setCursor(Cursor.WAIT) 有效。
【解决方案2】:

你的问题源于这行代码:

dialog.getDialogPane().setDisable(true);

不要禁用DialogPane,只需禁用Pane 上的Nodes。

您似乎问了不止一个问题。这回答了您的Cursor 问题。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2014-05-08
    • 1970-01-01
    • 1970-01-01
    • 2011-05-28
    • 2011-05-08
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多