【发布时间】:2017-10-05 06:52:03
【问题描述】:
我有一个带有主窗口的 JavaFX 应用程序。单击“创建用户”按钮后,将显示一个对话框以获取用户的输入。单击对话框上的“确定”按钮后,对话框被禁用,光标变为等待,而应用程序执行必要的任务来创建新用户。如果任务成功,对话框将关闭,并显示信息警报以宣布成功。
以下是我从实际代码中简化的代码,以重现我遇到的问题。以下是问题:
为什么 dialog.getDialogPane().setCursor(Cursor.WAIT) 不起作用?我可以使用 primaryStage.getScene().setCursor(Cursor.WAIT) 更改主窗口上的光标。但是如何更改对话框上的光标?
显示警报时,即使在显示警报之前调用了 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);
}
}
【问题讨论】:
-
发布您的用户类别。
-
我刚刚发布了用户类代码。