Wie lässt sich ein Passwortfeld realisieren?

Zur Passworteingabe stellt Java die Swing-Klasse JPasswordField bereit. Sie ist von JTextField abgeleitet, zeigt jedoch einige Besonderheiten.

Ein JPasswordField stellt, wie seine Elternklasse, ein einzeiliges Feld zur Aufnahme von Text dar, weist demgegenüber jedoch einige Besonderheiten auf:

Die Konstruktoren des JPasswordField sind fünffach überladen und entsprechen denen von JTextField. Ihnen können in unterschiedlichen Kombinationen Argumente für die Spaltenzahl, den eingegebenen Text und den Dokumenttyp der Eingabe übergeben werden.

Echo-Character ändern

Als Echo-Character werden die Platzhalterzeichen benannt, die die Klartextzeichen im Eingabefeld ersetzen und so ein unberechtigtes Auslesen verhindern sollen. JPasswordField verwendet als Standard einen Punkt '●', den Unicode-Character \u25cf, der dem Integer-Literal 9679 entspricht. Er kann durch die Methode setEchoChar​(char c) wie im folgenden Beispiel gezeigt geändert werden:

public class PasswortFeldBsp {

    public static void main(String[] args) {
        new PasswortFeldBsp().initGUI();
    }

    private void initGUI() {
        JPanel panel = new JPanel(new BorderLayout());
        JPasswordField pf = new JPasswordField(10);
        pf.setEchoChar('\u25ce');
        panel.add(pf, BorderLayout.CENTER);
        
        JFrame frame = new JFrame();
        frame.add(panel);
        frame.setTitle("Passwort-Feld");
        frame.pack();
        frame.setLocationRelativeTo(null);
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        frame.setVisible(true);
    }
}

Einem JFrame wird hier ein JPanel hinzugefügt, auf das zentrisch ein zehnspaltiges JPasswordField gesetzt ist. Der Ausdruck setEchoChar('\u25ce'); ändert den Echo-Character des Feldes auf das Zeichen \u25ce.

JPasswordField mit Echocharacter \u25ce

Wechsel der Anzeige

Möchte man eine Passworteingabe realisieren, die zwischen der maskierten Anzeige und dem Klartext wechselt, so kann die o.a. Methode verwendet werden. Als Echo-Character muss zur Anzeige des Klartextes dann '0' zugewiesen werden. Die folgende Methode wechselt zwischen beiden Darstellungsoptionen und kann etwa durch einen Button aufgerufen werden.

private void toggleView(JPasswordField field) {
    char c = field.getEchoChar();
    c = c == 0 ? (char) 9679 : (char) 0;
    field.setEchoChar(c);
}

Passwort kopieren

Das Kopieren eines Passworts durch Markieren und z.B. Eingabe von <Cmd>+<c> ist bei einem JPasswordField nicht möglich. Ein Kopieren in die Zwischenablage kann jedoch programmatisch erfolgen.

private void copyToClip(char[] c) {
    Clipboard clip = Toolkit.getDefaultToolkit().getSystemClipboard();
    StringSelection sel;
    String pass = new String(c);
    if (pass.length() > 0) {
        sel = new StringSelection(pass);
    } else {
        return;
    }
    clip.setContents(sel, null);
}

Das Beispiel zeigt eine vereinfachte Form der Übernahme des Passworts in die Zwischenablage. Für eine ausführlichere Diskussion der Zwischenablage sei auf den entsprechenden Artikel im Abschnitt Systemzugriff verwiesen.
Im Beispiel wird zunächst ein Clipboard-Objekt erzeugt, das die Funktionalität der System-Zwischenablage repräsentiert. Der Inhalt kann ihr nur als StringSelection übergeben werden. Das Objekt implementiert die Schnittstelle Transferable und speichert die Metadaten des zu übertragenden Inhalts.

Der folgende Quelltext fasst das bislang Gezeigte zusammen und erzeugt einen kleinen JFrame mit JPasswordField und zwei Buttons. Der rechte steuert den Wechsel des Echo-Characters, der linke veranlasst das Kopieren der Eingabe in die Zwischenablage.

JPasswordField mit Buttons zum Kopieren und Wechsel des Echo-Characters

public class PasswortFeld {

    public static void main(String[] args) {
        new PasswortFeld().initGUI();
    }
    
    private void initGUI() {
        JPanel panel = new JPanel(new BorderLayout());
        ImageIcon copyIcon = null, changeIcon = null;
        try {
            copyIcon = new ImageIcon(ImageIO.read(getClass().getResource("/img/copy.png")));
            changeIcon = new ImageIcon(ImageIO.read(getClass().getResource("/img/refresh.png")));
        } catch (IOException e1) {
            e1.printStackTrace();
        }
    
        JPasswordField pf = new JPasswordField(10);
        JButton changeButt = new JButton(changeIcon);
        changeButt.addActionListener(e -> toggleView(pf));
        JButton copyButt = new JButton(copyIcon);
        copyButt.addActionListener(e -> copyToClip(pf.getPassword()));
    
        panel.add(copyButt, BorderLayout.WEST);
        panel.add(pf, BorderLayout.CENTER);
        panel.add(changeButt, BorderLayout.EAST);
        JFrame frame = new JFrame();
        frame.add(panel);
        frame.setTitle("Passwort-Feld");
        frame.pack();
        frame.setLocationRelativeTo(null);
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        frame.setVisible(true);
    }
    
    private void toggleView(JPasswordField field) {
        char c = field.getEchoChar();
        c = c == 0 ? (char) 9679 : (char) 0;
        field.setEchoChar(c);
    }
    
    private void copyToClip(char[] c) {
        Clipboard clip = Toolkit.getDefaultToolkit().getSystemClipboard();
        StringSelection sel;
        String pass = new String(c);
    
        if (pass.length() > 0) {
            sel = new StringSelection(pass);
        } else {
            return;
        }
        clip.setContents(sel, null);
    }
}

Alternativer Anzeigewechsel

Eine etwas 'holprigere' Variante zum Wechsel zwischen Klartext und Maskierung der Eingabe besteht darin, das Eingabefeld zu tauschen. Sie ermöglicht gleichzeitig das Kopieren des Klartextes.
Das Prinzip besteht darin, durch eine Buttonaktion das JPasswordField gegen ein JTextField zu tauschen und den eingegebenen Text entsprechend zu setzen. Im folgenden Beispiel wird die Methode toggleField() durch einen Button aufgerufen. Sie wechselt zwischen beiden Eingabefeldern, setzt deren Sichtbarkeit, sowie die erfolgte Eingabe entsprechend und zeichnet schließlich das UI neu. Ist die Eingabe als Klartext sichtbar, kann sie durch Markieren und kopieren per Tastatur in die Zwischenablage übernommen werden, da die zugrunde liegende Komponente ein JTextField ist.

public class PasswortFeld {

    public static void main(String[] args) {
        new PasswortFeld().initGUI();

    }

    private void initGUI() {
        JPanel panel = new JPanel(new BorderLayout());
        ImageIcon changeIcon = null;
        try {
            changeIcon = new ImageIcon(ImageIO.read(getClass().getResource("/img/refresh.png")));
        } catch (IOException e1) {
            e1.printStackTrace();
        }

        JPasswordField pf = new JPasswordField(10);
        pf.setVisible(true);
        JTextField tf = new JTextField(10);
        tf.setVisible(false);

        JButton changeButt = new JButton(changeIcon);
        changeButt.addActionListener(e -> toggleField(panel, tf, pf));

        panel.add(pf, BorderLayout.CENTER);
        panel.add(changeButt, BorderLayout.EAST);
        JFrame frame = new JFrame();
        frame.add(panel);
        frame.setTitle("Passwort-Feld");
        frame.pack();
        frame.setLocationRelativeTo(null);
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        frame.setVisible(true);
    }

    private void toggleField(JPanel panel, JTextField tf, PasswordField pf) {
        if (tf.isVisible()) {
            pf.setText(tf.getText());
            tf.setVisible(false);
            panel.add(pf, BorderLayout.CENTER);
            pf.setVisible(true);
        } else {
            tf.setText(new String(pf.getPassword()));
            pf.setVisible(false);
            panel.add(tf, BorderLayout.CENTER);
            tf.setVisible(true);
        }
        panel.updateUI();
    }
}