重要的
此代码适用于以下特定情况:您的代码不在 JavaFX 应用程序线程上,并且您想要调用 JavaFX 应用程序线程上的代码向用户显示 GUI,然后在继续处理之前从该 GUI 获取结果关闭 JavaFX 应用程序线程。
在下面的代码片段中调用 CountdownLatch.await 时,您不能在 JavaFX 应用程序线程上。如果您在 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();
}
}
上述程序将密码打印到屏幕和控制台纯粹是出于演示目的,显示或记录密码不是您在真实应用程序中会做的事情。