Posts Tagged ‘TextBox’

JavaFX Password Field

September 12th, 2009

As I mentioned in My First Experience with JavaFX blog, there is no password field in JavaFX, so I had to google for some workarounds. Although I found a few, none of them worked flawlessly, so last night I decided to spend some time trying to come up with a password field that would really work as expected. And, I think I managed to come up with an elegant and simple solution. No hacking in form of covering the text area with additional components or adding effects that blur the text box (including the caret and component borders). It looks and behaves exactly as you would expect of a password field. Click on the following picture to try it out:

Or click the following button for standalone mode:

And here is how it is implemented:

import javafx.scene.control.TextBox;
import javafx.util.Math;

/** * @author Martin Matula */
public class PasswordBox extends TextBox {
    public-read var password = "";

    override function replaceSelection(arg) {
        var pos1 = Math.min(dot, mark);
        var pos2 = Math.max(dot, mark);
        password = "{password.substring(0, pos1)}{arg}{password.substring(pos2)}";
        super.replaceSelection(getStars(arg.length()));
    }

    override function deleteNextChar() {
        if ((mark == dot) and (dot < password.length())) {
            password = "{password.substring(0, dot)}{password.substring(dot + 1)}";
        }
        super.deleteNextChar();
    }

    override function deletePreviousChar() {
        if ((mark == dot) and (dot > 0)) {
            password = "{password.substring(0, dot - 1)}{password.substring(dot)}";
        }
        super.deletePreviousChar();
    }

    function getStars(len: Integer): String {
        var result: String = "";
        for (i in [1..len]) {
            result = "{result}*";
        }
        result;
    }
}

Quite simple, isn’t it? Here is how it is used in the Main class:

import javafx.stage.Stage;
import javafx.scene.Scene;
import javafx.scene.text.Text;

var password: PasswordBox;

var stage: Stage = Stage {
    title: "PasswordBox Demo"
    width: 200
    height: 100
    scene: Scene {
        content: [
            password = PasswordBox {
                translateX: 10
                translateY: 10
                columns: 20
            },
            Text {
                x: 10
                y: 50
                content: bind password.password
            }
        ]
    }
}

I guess there is still a room for improving the API – the real password is stored in the password property, while the text property became useless and should never be set by a client. If you want to populate the field with a remembered password, you need to do it by calling replaceSelection("password") on the password field after it’s initialization (rather than setting the text or the password properties). Anyway, I wanted to keep the code simple so that you can easily see the basic idea behind it.