2012-12-10 10 views
11

Ich arbeite an JavaFX-Anwendung, in meinem Szenario ist eine Passworteingabe in JavaFX erstellt, die Passwort mit zwei Optionen OK und Cancel nimmt. Ich habe das vom Benutzer eingegebene Passwort zurückgegeben.Ergebnis der Javafx-Plattform zurückgeben runlater

Meine Klasse Passwort-Dialog zu zeigen ist -

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

Mein Code, in der Passwortabfrage zu zeigen, ist unten, tatsächlich wird diese Aufforderung über andere UI angezeigt werden, so muß ich diese in Platform.runlater() umschliessen, es anders wirft Not on FX application thread. Ich brauche diese Passwortaufforderung, um angezeigt zu werden, bis ich die richtige bekomme. Wie kann ich den Wert eines Passworts erhalten, wenn ich das Passwort innerhalb von runlater anzeigen lasse?

Gibt es noch einen besseren Weg?

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

Antwort

27

Ich würde empfehlen, den Code innerhalb eines FutureTask Objekts zu wickeln. FutureTask ist ein Konstrukt, das (unter anderem) nützlich ist, um einen Teil des Codes in einem Thread (normalerweise ein Worker, in Ihrem Fall die Ereigniswarteschlange) auszuführen und ihn sicher auf einem anderen Thread abzurufen. FutureTask#get wird blockiert, bis FutureTask#run aufgerufen wurde, damit Ihr Passwort Prompt könnte wie folgt aussehen:

final FutureTask query = new FutureTask(new Callable() { 
    @Override 
    public Object call() throws Exception { 
     return queryPassword(); 
    } 
}); 
Platform.runLater(query); 
System.out.println(query.get()); 

Als FutureTask Runnable implementiert, können Sie es direkt an Platform#runLater(...) passieren. queryPassword() wird in die Ereigniswarteschlange übernommen, und der nachfolgende Aufruf erhält Blockierung, bis diese Methode abgeschlossen ist. Natürlich möchten Sie diesen Code in einer Schleife aufrufen, bis das Passwort tatsächlich übereinstimmt.

8

Wichtige

Dieser Code ist für den spezifischen Fall, wenn Sie Code haben, die nicht auf dem JavaFX Anwendungs-Thread ist, und Sie möchten Code aufzurufen, die auf der JavaFX-Anwendung Thread GUI angezeigt zu Ein Benutzer erhält dann ein Ergebnis von dieser GUI, bevor die Verarbeitung des JavaFX-Anwendungsthreads fortgesetzt wird.

Sie dürfen nicht im JavaFX-Anwendungs-Thread sein, wenn Sie CountdownLatch.await im folgenden Code-Snippet aufrufen. Wenn Sie CountDownLatch.await im JavaFX-Anwendungsthread aufrufen, wird die Anwendung deadlockiert. Wenn Sie sich bereits im JavaFX-Anwendungsthread befinden, müssen Sie Platform.runLater nicht aufrufen, um etwas im JavaFX-Anwendungsthread auszuführen.

Die meiste Zeit wissen Sie, ob Sie auf dem JavaFX-Anwendungsthread sind oder nicht. Wenn Sie nicht sicher sind, können Sie Ihren Thread überprüfen, indem Sie Platform.isFxApplicationThread() aufrufen.


Ein alternatives Verfahren CountDownLatch verwenden. Ich mag Sarcan Methode besser obwohl ;-)

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

Hier einige ausführbare Beispielcode Verwendung eines CountdownLatch demonstriert ist, die Ausführung eines nicht JavaFX Anwendungsthread zu suspendieren, bis ein JavaFX Dialog ein Ergebnis abgerufen hat denen dann wird vom nicht-JavaFX-Anwendungsthread zugegriffen.

Die Anwendung verhindert, dass der JavaFX-Launcher-Thread für die Anwendung fortgesetzt wird, bis der Benutzer das richtige Kennwort in einem JavaFX-Dialogfeld eingegeben hat. Die Zugriffsstufe wird erst angezeigt, wenn das richtige Passwort eingegeben wurde.

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

Das obige Programm druckt Passwort auf den Bildschirm und Konsole lediglich zu Demonstrationszwecken, Anzeigen oder Passwörter Anmeldung ist nicht etwas, das Sie in einer realen Anwendung tun würden.

+0

Aus irgendeinem seltsamen Grund funktioniert das nicht wie erwartet. Es blieb bei warten und der Runnable.run wurde nie aufgerufen. – xar

+0

Es funktioniert für mich, fügte ich ein ausführbares Beispiel hinzu, um die Verwendung weiter zu demonstrieren. – jewelsea

+0

@xar Sie haben wahrscheinlich 'latch.await()' im JavaFX-Anwendungsthread aufgerufen, wodurch Ihre App blockiert würde. Ich fügte der Antwort etwas Text hinzu, um es zu erklären. – jewelsea

Verwandte Themen