JPasswordFieldの可視化で数字の色のみ変更
Total: 34
, Today: 34
, Yesterday: 0
Posted by aterai at
Last-modified:
Summary
JPasswordField
に入力されたパスワードを可視化したとき、数値のみ色を変更して字形が似たアルファベットとの判別を簡単にします。
Screenshot

Advertisement
Source Code Examples
JPasswordField password = new JPasswordField(40);
password.setFont(FONT);
password.setText("!1l2c$%34e5&6#7=8g9O0");
JTextPane revealPassword = makeRevealPassword(password);
CardLayout cardLayout = new CardLayout();
JPanel p = new JPanel(cardLayout) {
@Override public void updateUI() {
super.updateUI();
setAlignmentX(RIGHT_ALIGNMENT);
}
};
p.add(password, PasswordField.HIDE.toString());
p.add(revealPassword, PasswordField.SHOW.toString());
AbstractButton button = new JToggleButton();
button.addActionListener(e -> {
boolean b = ((AbstractButton) e.getSource()).isSelected();
if (b) {
copyText(password.getDocument(), revealPassword.getStyledDocument());
cardLayout.show(p, PasswordField.SHOW.toString());
} else {
copyText(revealPassword.getStyledDocument(), password.getDocument());
cardLayout.show(p, PasswordField.HIDE.toString());
}
});
initEyeButton(button);
JPanel panel = new OverlayLayoutPanel();
panel.add(button);
panel.add(p);
// ...
class HighlightDocumentFilter extends DocumentFilter {
private final SimpleAttributeSet defAttr = new SimpleAttributeSet();
private final SimpleAttributeSet numAttr = new SimpleAttributeSet();
private final Pattern pattern = Pattern.compile("\\d");
protected HighlightDocumentFilter() {
super();
StyleConstants.setForeground(defAttr, Color.BLACK);
StyleConstants.setForeground(numAttr, Color.RED);
}
@Override public void insertString(
FilterBypass fb, int offset, String text, AttributeSet attr)
throws BadLocationException {
super.insertString(fb, offset, text, attr);
update(fb);
}
@Override public void remove(
FilterBypass fb, int offset, int length)
throws BadLocationException {
super.remove(fb, offset, length);
update(fb);
}
@Override public void replace(
FilterBypass fb, int offset, int length, String text, AttributeSet attrs)
throws BadLocationException {
super.replace(fb, offset, length, text, attrs);
update(fb);
}
private void update(FilterBypass fb) throws BadLocationException {
StyledDocument doc = (StyledDocument) fb.getDocument();
String text = doc.getText(0, doc.getLength());
doc.setCharacterAttributes(0, doc.getLength(), defAttr, true);
Matcher m = pattern.matcher(text);
while (m.find()) {
doc.setCharacterAttributes(m.start(), m.end() - m.start(), numAttr, true);
}
}
}
View in GitHub: Java, KotlinDescription
JPasswordField#setEchoChar(...) + HighlightFilter
JPasswordField#setEchoChar(...)
をオーバーライドし、エコー文字として0
(ヌル文字、\u0000
)が設定されパスワードが可視化された場合は、数値のみHighlighter
を使用して強調表示するDocumentFilter
を追加0
以外のエコー文字(このサンプルではUIManager.get("PasswordField.echoChar")
で取得した文字)が設定された場合は、Highlighter#removeAllHighlights()
で全ハイライトの削除と上記のDocumentFilter
の削除を実行
class DigitHighlightPasswordField extends JPasswordField {
protected DigitHighlightPasswordField(int columns) {
super(columns);
}
@Override public void setEchoChar(char c) {
super.setEchoChar(c);
Document doc = getDocument();
if (doc instanceof AbstractDocument) {
boolean reveal = c == '\u0000';
if (reveal) {
((AbstractDocument) doc).setDocumentFilter(new HighlightFilter(this));
try {
doc.remove(0, 0);
} catch (BadLocationException ex) {
UIManager.getLookAndFeel().provideErrorFeedback(this);
}
} else {
getHighlighter().removeAllHighlights();
((AbstractDocument) doc).setDocumentFilter(null);
}
}
}
}
CardLayout + (JPasswordField <> JTextPane)
- JPasswordFieldでパスワードを可視化すると同様に
CardLayout
でJPasswordField
と数値のみ文字色(スタイル)を変更するDocumentFilter
を設定したJTextPane
を使用して可視状態を切り替える JTextPane
はJTextPaneを一行に制限してスタイル可能なJTextFieldとして使用すると同様に一行に制限JPasswordField
とJTextPane
のDocument
は共有できないので切り替え時にDocument#getText(...)
、Document#insertString(...)
でパスワードをコピーしている
- JPasswordFieldでパスワードを可視化すると同様に