我正在尝试在 JavaFX 中制作一个带有小进度条的登录页面。但每次我想检查凭据时,任务都会失败并将我扔到 setOnFailed() 方法中。我不知道是什么让它改变它的状态或如何让它工作。
这是迄今为止我的代码:
public class Login extends Base_controller implements Initializable{
private ProgressBar pb = new ProgressBar();
private TextField username;
private PasswordField password;
public void start(Stage primaryStage) throws Exception {
// Setting structure and components
Label username_lbl = new Label();
Label password_lbl = new Label();
username_lbl.setText("Username:");
password_lbl.setText("Password:");
username = new TextField();
password = new PasswordField();
//some code
VBox root = new VBox();
root.setAlignment(Pos.CENTER);
root.getChildren().addAll(container0, container1, container2, container3);
root.setSpacing(30);
// button action listener
test.setOnAction(e->{
Platform.runLater(() -> {
root.getChildren().add(pb);
});
Task<Void> validatePassword = new Task<Void>(){
@Override
protected Void call() throws Exception {
validatePassword(password, username);
return null;
}
};
validatePassword.setOnSucceeded(ee->{ // when it finishes successfully
try {
root.getChildren().remove(pb); // remove the progress bar
} catch (Exception e1) {
e1.printStackTrace();
}
User = dbHandler.getPersonByUsername(username.getText()); // Set up global variable
Role = dbHandler.getPersonRole(User.getEmail());
MainStage = (Stage) anchorPane.getScene().getWindow();
Parent parent = null;
try {
parent = FXMLLoader.load(getClass().getResource("/menu.fxml"));
} catch (IOException e1) {
e1.printStackTrace();
}
Scene scene = new Scene(parent);
MainStage.setScene(scene);
MainStage.setTitle("Menu | Administration of Musical Courses");
MainStage.show();
});
validatePassword.setOnFailed(eee->{ // if it fails (that will be indicated by the returned alert message)
System.out.println("Failed");
try {
root.getChildren().remove(pb); // remove it anyway but inform your user
Alert alert = new Alert(Alert.AlertType.ERROR, "Wrong Password", ButtonType.OK);
alert.showAndWait();
} catch (Exception e1) {
e1.printStackTrace();
}
});
new Thread(validatePassword).start(); // add the task to a thread and start it
});
Scene scene = new Scene(root, 600,400);
primaryStage.setScene(scene);
primaryStage.setTitle("Login | Administration of Musical Courses");
primaryStage.show();
}
// validate here in this method
public void validatePassword(TextField password, TextField username)
if (checkLogin()) {
new Alert(Alert.AlertType.ERROR);
}
}
public boolean checkLogin(){
return BCrypt.checkpw(password.getText(), dbHandler.getLoginByUsername(username.getText()).getPassword());
}
}
从数据库获取数据时,validatePassword 方法总是失败。调用数据库是否有可能导致任务失败?如何更改代码以使其正常工作?
最佳答案
当且仅当 call()
方法抛出异常时,任务才会进入失败状态。您可以将 validatePassword.getException().printStackTrace()
放入 onFailed
处理程序中以查看异常的堆栈跟踪,然后您可以read to see what went wrong :
validatePassword.setOnFailed(eee->{ // if it fails (that will be indicated by the returned alert message)
System.out.println("Failed");
validatePassword.getException().printStackTrace();
try {
root.getChildren().remove(pb); // remove it anyway but inform your user
Alert alert = new Alert(Alert.AlertType.ERROR, "Wrong Password", ButtonType.OK);
alert.showAndWait();
} catch (Exception e1) {
e1.printStackTrace();
}
});
我不太明白你的 validatePassword()
方法:
if (checkLogin()) {
new Alert(...);
}
如果checkLogin()
返回true,这将创建一个Alert
,但不会实际使用它(你在这里真正的意图是什么......?)。请注意,此方法是从后台线程调用的(因为它是从任务的 call()
方法调用的),如果您不这样做,则创建 Alert
是非法的在 FX 应用程序线程上。所以我怀疑这会导致抛出异常,从而将您发送到 onFailed
处理程序:检查堆栈跟踪将确认这一点。
更自然的方法是让任务返回一个 Boolean
表示登录是否成功,然后您可以在 onSucceeded
处理程序中处理该值:
test.setOnAction(e->{
Platform.runLater(() -> {
root.getChildren().add(pb);
});
Task<Boolean> validatePassword = new Task<Boolean>(){
@Override
protected Boolean call() throws Exception {
return checkLogin();
}
};
validatePassword.setOnSucceeded(ee->{ // when it finishes successfully
// this cannot throw an exception, there is no need for a try-catch;
root.getChildren().remove(pb); // remove the progress bar
if (validatePassword.getValue()) {
User = dbHandler.getPersonByUsername(username.getText()); // Set up global variable
Role = dbHandler.getPersonRole(User.getEmail());
MainStage = (Stage) anchorPane.getScene().getWindow();
Parent parent = null;
try {
parent = FXMLLoader.load(getClass().getResource("/menu.fxml"));
} catch (IOException e1) {
e1.printStackTrace();
}
Scene scene = new Scene(parent);
MainStage.setScene(scene);
MainStage.setTitle("Menu | Administration of Musical Courses");
MainStage.show();
} else {
// handle failed login... this is on the FX Application Thread so
// you can show an Alert...
Alert alert = new Alert(Alert.AlertType.ERROR, "Wrong Password", ButtonType.OK);
alert.show();
}
});
validatePassword.setOnFailed(eee->{
// exception was thrown trying to validate password
validatePassword.getException().printStackTrace();
// inform user something went wrong...
Alert alert = new Alert(Alert.AlertType.ERROR, "Something went wrong", ButtonType.OK);
alert.show();
});
new Thread(validatePassword).start(); // add the task to a thread and start it
});
关于每次我想要获取登录信息时,JavaFX 任务都会将状态更改为失败,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/44143340/