Подтвердить что ты не робот

Результат возврата от платформы javafx platform runter

Я работаю над приложением 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;
    }

Мой код, где будет отображаться пароль, приведен ниже, на самом деле это приглашение будет отображаться поверх другого пользовательского интерфейса, поэтому мне нужно вставить его внутри 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(""));
4b9b3361

Ответ 1

Я бы рекомендовал обернуть код внутри объекта 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 в очереди событий, а последующий вызов получить блок до тех пор, пока этот метод не завершится. Конечно, вы захотите вызвать этот код в цикле до тех пор, пока пароль не будет действительно соответствовать.

Ответ 2

Внимание!

Этот код предназначен для конкретного случая, когда у вас есть код, который отсутствует в потоке приложения JavaFX, и вы хотите вызвать код, который находится в потоке приложений JavaFX, для отображения графического интерфейса пользователя, а затем получить результат из этого графического интерфейса прежде чем продолжить обработку потока приложений JavaFX.

Вы не должны быть в потоке приложений JavaFX, когда вы вызываете CountdownLatch.await в фрагменте кода ниже. Если вы вызовете CountDownLatch.await в потоке приложений JavaFX, вы закроете свое приложение. Кроме того, если вы уже находитесь в потоке приложений 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. Предоставленный этап доступа не отображается, пока не будет введен правильный пароль.

enterpassword   access granted

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();
  }
}

Вышеупомянутая программа печатает пароль на экране и консоль исключительно для демонстрационных целей, отображение или регистрация паролей - это не то, что вы могли бы сделать в реальном приложении.