Code
class PinCodeDocumentFilter extends DocumentFilter {
public static final int MAX = 4;
@Override public void replace(
DocumentFilter.FilterBypass fb, int offset,
int length, String text, AttributeSet attrs) throws BadLocationException {
String str = fb.getDocument().getText(
0, fb.getDocument().getLength()) + text;
if (str.length() <= MAX && str.matches("\\d+")) {
super.replace(fb, offset, length, text, attrs);
}
}
}
class PasswordView2 extends PasswordView {
public PasswordView2(Element elem) {
super(elem);
}
@Override protected int drawUnselectedText(
Graphics g, int x, int y, int p0, int p1) throws BadLocationException {
return drawText(g, x, y, p0, p1);
}
// @see drawUnselectedTextImpl(...)
private int drawText(Graphics g, int x, int y, int p0, int p1)
throws BadLocationException {
Container c = getContainer();
int j = x;
if (c instanceof JPasswordField) {
JPasswordField f = (JPasswordField) c;
if (f.isEnabled()) {
g.setColor(f.getForeground());
} else {
g.setColor(f.getDisabledTextColor());
}
Graphics2D g2 = (Graphics2D) g;
char echoChar = f.getEchoChar();
int n = p1 - p0;
// Override BasicPasswordFieldUI#create(Element) to return PasswordView2
// that makes only trailing digits visible without masking
for (int i = 0; i < n; i++) {
j = i == n - 1
? drawLastChar(g2, j, y, i)
: drawEchoCharacter(g, j, y, echoChar);
}
}
return j;
}
private int drawLastChar(Graphics g, int x, int y, int p1)
throws BadLocationException {
Graphics2D g2 = (Graphics2D) g;
Font font = g2.getFont();
float fs = font.getSize2D();
double w = font.getStringBounds("0", g2.getFontRenderContext()).getWidth();
int sz = (int) ((fs - w) / 2d);
Document doc = getDocument();
Segment s = new Segment(); // SegmentCache.getSharedSegment();
doc.getText(p1, 1, s);
// int ret = Utilities.drawTabbedText(s, x, y, g, this, p1);
// SegmentCache.releaseSharedSegment(s);
return Utilities.drawTabbedText(s, x + sz, y, g, this, p1);
}
}
References