How to unmask a JavaFX PasswordField or properly mask a TextField?

I know this is older, but i was searching for answer and this is my solution:

@FXML
private JFXButton showpassword;
private String password;

showpassword.addEventFilter(MouseEvent.MOUSE_PRESSED, e -> {
            password = passwordField.getText();
            passwordField.clear();
            passwordField.setPromptText(password);
        });
        showpassword.addEventFilter(MouseEvent.MOUSE_RELEASED, e -> {
            passwordField.setText(password);
            passwordField.setPromptText("Password");
        });

Using button with graphic like "WIN10 Eye - unmask password"


> However, I cannot find anything in the JavaFX API that let me do that?

The PasswordField component does not display masked text by default. However you can use PasswordField with TextField and toggle masked/unmasked text using these components respectively. Where the unmasked text is shown by TextField, as in example demo below.

> I would like to use a TextField that display the last key pressed for only half a second or until next key is pressed, and then he shall mask all previous user input.

Since PasswordField, itself is a extended version of TextField. You can always build your own custom password textbox with properties you mentioned.

> is there a way for me to get hold of the OS dependent (I think it is OS dependent??) password echo character I should use?

Frankly did not grab what you are saying here. You can track text changes by adding change listener to PasswordField.textPrperty() and do animations, timers etc. You can override the default bullet mask by extending PasswordFieldSkin and using it through CSS -fx-skin. See the definition of bullet in its source here:

public class PasswordFieldSkin extends TextFieldSkin {
    public static final char BULLET = '\u2022';

    public PasswordFieldSkin(PasswordField passwordField) {
        super(passwordField, new PasswordFieldBehavior(passwordField));
    }

    @Override protected String maskText(String txt) {
        TextField textField = getSkinnable();

        int n = textField.getLength();
        StringBuilder passwordBuilder = new StringBuilder(n);
        for (int i=0; i<n; i++) {
            passwordBuilder.append(BULLET);
        }

        return passwordBuilder.toString();
    }
}

Finally, Here is kick off demo app of showing password characters using bindings:

@Override
public void start(Stage primaryStage) {

    // text field to show password as unmasked
    final TextField textField = new TextField();
    // Set initial state
    textField.setManaged(false);
    textField.setVisible(false);

    // Actual password field
    final PasswordField passwordField = new PasswordField();

    CheckBox checkBox = new CheckBox("Show/Hide password");

    // Bind properties. Toggle textField and passwordField
    // visibility and managability properties mutually when checkbox's state is changed.
    // Because we want to display only one component (textField or passwordField)
    // on the scene at a time.
    textField.managedProperty().bind(checkBox.selectedProperty());
    textField.visibleProperty().bind(checkBox.selectedProperty());

    passwordField.managedProperty().bind(checkBox.selectedProperty().not());
    passwordField.visibleProperty().bind(checkBox.selectedProperty().not());

    // Bind the textField and passwordField text values bidirectionally.
    textField.textProperty().bindBidirectional(passwordField.textProperty());

    VBox root = new VBox(10);
    root.getChildren().addAll(passwordField, textField, checkBox);
    Scene scene = new Scene(root, 300, 250);
    primaryStage.setTitle("Demo");
    primaryStage.setScene(scene);
    primaryStage.show();
}

You need create three elements:

  • TextField : the password visible field
  • PasswodField : the password not visible field
  • CheckBox : the toggle visibility field

You place the passwords fields in the same position(x, y):

<PasswordField fx:id="pass_hidden" layoutX="X" layoutY="Y" />
<TextField fx:id="pass_text" layoutX="X" layoutY="Y"/>
<CheckBox fx:id="pass_toggle" onAction="#togglevisiblePassword" .... />

Note: Replaces the value of X and Y.

Add in your controller:

@FXML
private TextField pass_text;
@FXML
private CheckBox pass_toggle;
@FXML
private Button btn_start_stop;

/**
 * Controls the visibility of the Password field
 * @param event
 */
@FXML
public void togglevisiblePassword(ActionEvent event) {
    if (pass_toggle.isSelected()) {
        pass_text.setText(pass_hidden.getText());
        pass_text.setVisible(true);
        pass_hidden.setVisible(false);
        return;
    }
    pass_hidden.setText(pass_text.getText());
    pass_hidden.setVisible(true);
    pass_text.setVisible(false);
}

//Run
@Override
public void initialize(URL location, ResourceBundle resources) {
    this.togglevisiblePassword(null);
}

If you want to know the value of the password you can create a method that returns it:

private String passwordValue() {
    return pass_toggle.isSelected()?
       pass_text.getText(): pass_hidden.getText();
}