我正在研究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;
}
Run Code Online (Sandbox Code Playgroud)
我的代码显示密码提示的位置如下,实际上这个提示将显示在其他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(""));
Run Code Online (Sandbox Code Playgroud)
sar*_*can 36
我建议将代码包装在一个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());
Run Code Online (Sandbox Code Playgroud)
作为FutureTask实现Runnable,您可以直接将其传递给Platform#runLater(...).queryPassword()将被忽略在事件队列上,并随后调用get块直到该方法完成.当然,您需要在循环中调用此代码,直到密码实际匹配为止.
jew*_*sea 10
重要
此代码适用于特定情况,当您拥有不在JavaFX应用程序线程上的代码并且您想要调用JavaFX应用程序线程上的代码以向用户显示GUI,然后在继续处理之前从该GUI获取结果关闭JavaFX应用程序线程.
当您在下面的代码片段中调用CountdownLatch.await时,您不能在JavaFX应用程序线程上.如果在JavaFX Application线程上调用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());
Run Code Online (Sandbox Code Playgroud)
下面是一些可执行的示例代码,演示如何使用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();
}
}
Run Code Online (Sandbox Code Playgroud)
上面的程序只是为了演示目的而在屏幕和控制台上打印密码,显示或记录密码不是你在实际应用程序中要做的事情.