Javafx 2 从javafx平台runlater返回结果

Javafx 2 从javafx平台runlater返回结果,javafx-2,javafx,Javafx 2,Javafx,我正在开发JavaFX应用程序,在我的场景中,将显示一个在JavaFX中创建的密码提示,该提示使用两个选项OK和Cancel。我已返回用户输入的密码 我的显示密码对话框的类是- public static String showPasswordDialog(String title, String message, Stage parentStage, double w, double h) { try { Stage stage = new Stage();

我正在开发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()
,否则它将在FX应用程序线程上抛出
。我需要这个密码提示显示,直到我得到正确的一个。如果我将显示密码包含在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,并在该方法完成之前调用get block。当然,您需要在循环中调用此代码,直到密码真正匹配为止。

重要信息

此代码适用于以下特定情况:您有不在JavaFX应用程序线程上的代码,并且希望调用JavaFX应用程序线程上的代码向用户显示GUI,然后在继续处理JavaFX应用程序线程之前从该GUI获取结果

在下面的代码段中调用CountdownLatch.await时,您不能处于JavaFX应用程序线程上。如果在JavaFX应用程序线程上调用CountDownLatch.await,将使应用程序死锁。此外,如果您已经在JavaFX应用程序线程上,则不需要调用Platform.runLater在JavaFX应用程序线程上执行某些操作

大多数情况下,您都知道自己是否在JavaFX应用程序线程上。如果您不确定,可以通过调用来检查线程


另一种方法是使用。不过我更喜欢Sarcan的方法;-)


下面是一些可执行示例代码,演示如何使用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();
  }
}

导入javafx.application.*;
导入javafx.beans.property.*;
导入javafx.event.ActionEvent;
导入javafx.event.EventHandler;
导入javafx.geometry.Pos;
导入javafx.scene.scene;
导入javafx.scene.control.*;
导入javafx.scene.layout.*;
导入javafx.scene.text.TextAlignment;
导入javafx.stage.*;
导入java.util.concurrent.CountDownLatch;
公共类密码提示器扩展应用程序{
final StringProperty passwordProperty=新的SimpleStringProperty();
@重写公共void init(){
最终倒计时闩锁=新倒计时闩锁(1);
Platform.runLater(新的Runnable(){
@重写公共无效运行(){
set(新的PasswordPrompt(null).getPassword());
倒计时();
}
});
试一试{
satch.wait();
}捕捉(中断异常e){
Platform.exit();
}
System.out.println(passwordProperty.get());
}
@覆盖公共无效开始(最后阶段){
Label welcomeMessage=新标签(“使用密码\n授予访问权限”+passwordProperty.get());
welcomeMessage.setTextAlignment(TextAlignment.CENTER);
StackPane布局=新建StackPane();
布局。设置样式(“-fx背景色:玉米丝;-fx填充:20px;”);
layout.getChildren().setAll(welcomeMessage);
舞台场景(新场景(布局));
stage.show();
}
公共静态void main(字符串[]args){launch(args);}
}
类密码提示{
最终窗口所有者;
密码提示(窗口所有者){
this.owner=所有者;
}
公共字符串getPassword(){
最终阶段对话框=新阶段();
setTitle(“Pass是芝麻”);
dialog.initOwner(所有者);
initStyle(StageStyle.UTILITY);
初始化模态(模态窗口模态);
setOnCloseRequest(新的EventHandler(){
@重写公共无效句柄(WindowEvent WindowEvent){
Platform.exit();
}
});
最终文本字段TextField=新文本字段();
setPrompText(“输入芝麻”);
最终按钮提交按钮=新按钮(“提交”);
submitButton.setDefaultButton(true);
setOnAction(新的EventHandler()){
@重写公共无效句柄(ActionEvent t){
if(“sesame”.equals(textField.getText())){
dialog.close();
}
}
});
最终VBox布局=新的VBox(10);
布局。设置对齐(位置中间\右侧);
layout.setStyle(“-fx背景色:azure;-fx填充:10;”);
layout.getChildren().setAll(textField,submitButton);
dialog.setScene(新场景(布局));
dialog.showAndWait();
返回textField.getText();
}
}

上面的程序将密码打印到屏幕和控制台纯粹是为了演示,显示或记录密码不是在实际应用程序中可以做的事情。

出于某种奇怪的原因,这无法按预期工作。它在await时卡住了,从未调用过Runnable.run。它对我有效,我添加了一个可执行示例以进一步演示其用法。@xar您可能在JavaFX ap上调用了
latch.await()
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();
  }
}