我工作在JavaFX应用程序,在我的情况是显示在JavaFX中创建一个密码提示这需要密码有两个选项, OK
和Cancel
。 我已经回到由用户输入的密码。
我的班级显示密码对话框的是 -
public static String showPasswordDialog(String title, String message, Stage parentStage, double w, double h) {
try {
Stage stage = new Stage();
PasswordDialogController controller = (PasswordDialogController) Utility.replaceScene("Password.fxml", stage);
passwordDialogController.init(stage, message, "/images/password.png");
if (parentStage != null) {
stage.initOwner(parentStage);
}
stage.initModality(Modality.WINDOW_MODAL);
stage.initStyle(StageStyle.UTILITY);
stage.setResizable(false);
stage.setWidth(w);
stage.setHeight(h);
stage.showAndWait();
return controller.getPassword();
} catch (Exception ex) {
return null;
}
我的代码在哪里显示密码提示低于,居然会被显示在其他UI此提示,所以我需要附寄这里面Platform.runlater()
否则它会引发Not on FX application thread
。 我需要显示此提示输入密码,直到我得到正确的。 我怎样才能得到密码的值,如果我围封显示里面runlater密码。
有没有其他更好的办法?
final String sPassword = null;
do {
Platform.runLater(new Runnable() {
@Override
public void run() {
sPassword = JavaFXDialog.showPasswordDialog(sTaskName + "Password", "Enter the password:", parentStage, 400.0, 160.0);
}
});
if (sPassword == null) {
System.out.println("Entering password cancelled.");
throw new Exception("Cancel");
}
} while (sPassword.equalsIgnoreCase(""));
我建议一个包裹内的代码FutureTask
对象。 FutureTask
是在一个线程中执行的代码的一部分(通常是工人,你的情况的事件队列),并安全地取回它在另一个有用的一个结构(除其他事项外)。 FutureTask#get
将阻塞,直到FutureTask#run
已被调用,因此您的密码提示看起来是这样的:
final FutureTask query = new FutureTask(new Callable() {
@Override
public Object call() throws Exception {
return queryPassword();
}
});
Platform.runLater(query);
System.out.println(query.get());
作为FutureTask
实现了Runnable,你可以直接将它传递给Platform#runLater(...)
queryPassword()
将在事件队列中inokved,并且直到该方法完成随后的调用来获取块。 当然,你会想在一个循环中调用此代码,直到密码确实匹配。
重要
此代码是当你有代码是不是JavaFX应用程序线程上的特定情况下 ,你要调用的代码是JavaFX应用程序的线程来显示图形用户界面给用户,然后从继续处理之前GUI得到的结果关闭JavaFX应用程序线程。
您一定不能是JavaFX应用程序线程,当你在下面的代码片段调用CountdownLatch.await。 如果JavaFX应用程序线程调用CountDownLatch.await,你会死锁您的应用程序。 此外,如果您已经是JavaFX应用程序线程上,你不需要调用Platform.runLater执行JavaFX应用程序线程上的东西。
大多数时候,你知道,如果你是JavaFX应用程序的线程或不上。 如果你不知道,你可以通过调用检查你的线程Platform.isFxApplicationThread() 。
使用替代方法CountDownLatch 。 我喜欢Sarcan的方法虽然好;-)
final CountDownLatch latch = new CountDownLatch(1);
final StringProperty passwordProperty = new SimpleStringProperty();
Platform.runLater(new Runnable() {
@Override public void run() {
passwordProperty.set(queryPassword());
latch.countDown();
}
});
latch.await();
System.out.println(passwordProperty.get());
下面是一些可执行代码示例演示使用的CountDownLatch的直到一个JavaFX对话已检索其然后可以由非JavaFX应用程序线程访问的结果,暂停非JavaFX应用程序线程的执行。
该应用程序阻止了JavaFX启动线程来自持续,直到用户在JavaFX的对话框中输入正确的密码应用。 没有显示已授权访问阶段,直到正确的密码已输入。
import javafx.application.*;
import javafx.beans.property.*;
import javafx.event.ActionEvent;
import javafx.event.EventHandler;
import javafx.geometry.Pos;
import javafx.scene.Scene;
import javafx.scene.control.*;
import javafx.scene.layout.*;
import javafx.scene.text.TextAlignment;
import javafx.stage.*;
import java.util.concurrent.CountDownLatch;
public class PasswordPrompter extends Application {
final StringProperty passwordProperty = new SimpleStringProperty();
@Override public void init() {
final CountDownLatch latch = new CountDownLatch(1);
Platform.runLater(new Runnable() {
@Override public void run() {
passwordProperty.set(new PasswordPrompt(null).getPassword());
latch.countDown();
}
});
try {
latch.await();
} catch (InterruptedException e) {
Platform.exit();
}
System.out.println(passwordProperty.get());
}
@Override public void start(final Stage stage) {
Label welcomeMessage = new Label("Access Granted\nwith password\n" + passwordProperty.get());
welcomeMessage.setTextAlignment(TextAlignment.CENTER);
StackPane layout = new StackPane();
layout.setStyle("-fx-background-color: cornsilk; -fx-padding: 20px;");
layout.getChildren().setAll(welcomeMessage);
stage.setScene(new Scene(layout));
stage.show();
}
public static void main(String[] args) { launch(args); }
}
class PasswordPrompt {
final Window owner;
PasswordPrompt(Window owner) {
this.owner = owner;
}
public String getPassword() {
final Stage dialog = new Stage();
dialog.setTitle("Pass is sesame");
dialog.initOwner(owner);
dialog.initStyle(StageStyle.UTILITY);
dialog.initModality(Modality.WINDOW_MODAL);
dialog.setOnCloseRequest(new EventHandler<WindowEvent>() {
@Override public void handle(WindowEvent windowEvent) {
Platform.exit();
}
});
final TextField textField = new TextField();
textField.setPromptText("Enter sesame");
final Button submitButton = new Button("Submit");
submitButton.setDefaultButton(true);
submitButton.setOnAction(new EventHandler<ActionEvent>() {
@Override public void handle(ActionEvent t) {
if ("sesame".equals(textField.getText())) {
dialog.close();
}
}
});
final VBox layout = new VBox(10);
layout.setAlignment(Pos.CENTER_RIGHT);
layout.setStyle("-fx-background-color: azure; -fx-padding: 10;");
layout.getChildren().setAll(textField, submitButton);
dialog.setScene(new Scene(layout));
dialog.showAndWait();
return textField.getText();
}
}
上述程序将打印密码,屏幕和控制台纯粹是为了演示目的,显示或记录的密码是不是你会在实际应用做。