1

I have answered How to add letter spacing in Swing. However, this way does not seem to have impact for JPasswordField(s):

enter image description here

When I passwordField.setEchoChar((char)0), it works:

enter image description here

Is there a way to apply the spacing when the dots () are shown?

public class PasswordFieldLetterSpacing {

    public static void main(String[] args) {
        SwingUtilities.invokeLater(() -> {
            JPasswordField field = new JPasswordField(15);
            Map<TextAttribute, Object> attributes = new HashMap<TextAttribute, Object>();
            attributes.put(TextAttribute.TRACKING, 0.5);
            field.setFont(field.getFont().deriveFont(attributes));

            JLabel showPassLabel = new JLabel("move mouse here");
            showPassLabel.setCursor(Cursor.getPredefinedCursor(Cursor.HAND_CURSOR));
            showPassLabel.addMouseListener(new MouseAdapter() {
                @Override
                public void mouseEntered(MouseEvent ev) {
                    field.setEchoChar((char) 0);
                }

                @Override
                public void mouseExited(MouseEvent ev) {
                    field.setEchoChar((char) UIManager.get("PasswordField.echoChar"));
                }
            });

            JFrame frame = new JFrame("");
            frame.setLayout(new FlowLayout());

            frame.add(field);
            frame.add(showPassLabel);

            frame.pack();
            frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
            frame.setLocationByPlatform(true);
            frame.setVisible(true);
        });
    }

}

I don't know if look and feel plays a role on this. It seems to happen in both Windows Look and Feel and in the Java's default one.

George Z.
  • 6,643
  • 4
  • 27
  • 47

1 Answers1

1

As best as I can tell the non-echo text is painted in the PlainView class using the Utilities.drawTabbedText(...) method which would paint the text as a string so the text attributes work as expected.

However, for some reason it appears that the echo character is painted one at a time using the width of the character for spacinging, instead of painting the entire string at once:

protected float drawEchoCharacter(Graphics2D g, float x, float y, char c) {
    return drawEchoCharacterImpl(g, x, y, c, true);
}

private float drawEchoCharacterImpl(Graphics g, float x, float y,
                                    char c, boolean useFPAPI) {
    ONE[0] = c;
    SwingUtilities2.drawChars(Utilities.getJComponent(this),
                              g, ONE, 0, 1, x, y);
    if (useFPAPI) {
        return x + g.getFontMetrics().charWidth(c);
    } else {
        FontRenderContext frc = g.getFontMetrics().getFontRenderContext();
        return x + (float) g.getFont().getStringBounds(ONE, 0, 1, frc).getWidth();
    }
}

So I would guess you need to write a custom PasswordView class. (I have no idea how to do this).

Check out: the PasswordView for the full source.

camickr
  • 321,443
  • 19
  • 166
  • 288
  • I checked it and tried it a bit. Didn't manage to do it. Seems too much effort for what I want. Thanks anyway. – George Z. Sep 13 '21 at 16:43