0

I'm making login screen for a school project, and I want to give the user the ability to show and hide their password.

private PasswordField password;

How do I do this?

2
  • 2
    There's no API for this in the core implementation. A common suggestion I see on this site is to stack a PasswordField and TextField and toggle their visibility to simulate what you want. Or you can go all the way and implement a custom skin for PasswordField. Commented May 10, 2021 at 20:20
  • Yes, it did. I did do it a different way by implementing an HBox and use set(0, text/passwordField), but it works pretty much the same way. Commented May 12, 2021 at 10:50

1 Answer 1

1

There can be many other ways to implement this feature, but below is the approach by using a custom skin (as suggested by Slaw).

The general idea for the approach is :

  • adjust the default padding to reserve space for the toggle button to show/hide the password.
  • override the maskText method to update the text based on toggle button selection
  • as the text in the skin is bounded, reset the text value of the TextField to trigger the required methods (a bit dirty way)

Please check the below demo: (style the button to the desired icon)

enter image description here

import com.sun.javafx.scene.control.skin.TextFieldSkin;
import javafx.application.Application;
import javafx.beans.binding.DoubleBinding;
import javafx.geometry.Insets;
import javafx.scene.Scene;
import javafx.scene.control.Skin;
import javafx.scene.control.TextField;
import javafx.scene.control.ToggleButton;
import javafx.scene.layout.StackPane;
import javafx.stage.Stage;

public class TogglePasswordFieldDemo extends Application {
    @Override
    public void start(Stage primaryStage) throws Exception {
        StackPane root = new StackPane();
        root.setPadding(new Insets(10));
        Scene scene = new Scene(root, 320, 100);
        primaryStage.setScene(scene);
        primaryStage.setTitle("TogglePasswordField Demo");
        primaryStage.show();

        TogglePasswordField textField = new TogglePasswordField();
        root.getChildren().add(textField);
    }

    class TogglePasswordField extends TextField {
        @Override
        protected Skin<?> createDefaultSkin() {
            return new TogglePasswordFieldSkin(this);
        }
    }

    class TogglePasswordFieldSkin extends TextFieldSkin {
        ToggleButton show;

        public TogglePasswordFieldSkin(TogglePasswordField textField) {
            super(textField);
            textField.setPadding(new Insets(4, 25.0, 4, 7));

            show = new ToggleButton();
            show.setFocusTraversable(false);
            show.setMaxSize(15, 15);
            show.setMinSize(15, 15);
            show.setPadding(new Insets(0));
            show.selectedProperty().addListener((obs, old, selected) -> {
                // Resetting the text to invalidate the text property so that it will call the maskText method.
                String txt = textField.getText();
                int pos = textField.getCaretPosition();
                textField.setText(null);
                textField.setText(txt);
                textField.positionCaret(pos);
            });
            show.translateXProperty().bind(new DoubleBinding() {
                {
                    bind(textField.widthProperty(), show.widthProperty());
                }

                @Override
                protected double computeValue() {
                    return (textField.getWidth() - show.getWidth()) / 2;
                }
            });
            getChildren().add(show);
        }

        @Override
        protected String maskText(String txt) {
            if (show != null && !show.isSelected()) {
                int n = txt.length();
                StringBuilder passwordBuilder = new StringBuilder(n);
                for (int i = 0; i < n; i++) {
                    passwordBuilder.append(BULLET);
                }

                return passwordBuilder.toString();
            } else {
                return txt;
            }
        }
    }
}
Sign up to request clarification or add additional context in comments.

Comments