Результат возврата от платформы 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(""));
Ответы
Ответ 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. Предоставленный этап доступа не отображается, пока не будет введен правильный пароль.
![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();
}
}
Вышеупомянутая программа печатает пароль на экране и консоль исключительно для демонстрационных целей, отображение или регистрация паролей - это не то, что вы могли бы сделать в реальном приложении.