• category: swing folder: ShowHidePasswordField title: JPasswordFieldでパスワードを可視化する tags: [JPasswordField, JCheckBox, JToggleButton, OverlayLayout] tags: [JPasswordField, JCheckBox, JToggleButton, OverlayLayout, CardLayout] author: aterai pubdate: 2015-01-05T00:29:05+09:00 description: JPasswordFieldに入力したパスワードの表示・非表示を切り替えるためのボタンを作成し、これを入力欄などに配置します。 image: https://lh4.googleusercontent.com/-zXk3TZfF_v4/VPXFdo3UBzI/AAAAAAAANzU/VfiEUdm-aUI/s800/ShowHidePasswordField.png hreflang:
       href: http://java-swing-tips.blogspot.com/2015/01/showhide-passwordfield-using-cardlayout.html
       href: https://java-swing-tips.blogspot.com/2015/01/showhide-passwordfield-using-cardlayout.html
       lang: en

概要

JPasswordFieldのパスワードを可視化するため、ドキュメントを共有するJTextFieldを作成して、これをCardLayoutで切り替えます。

概要

JPasswordFieldに入力したパスワードの表示・非表示を切り替えるためのボタンを作成し、これを入力欄などに配置します。

サンプルコード

サンプルコード

JPasswordField pf = new JPasswordField(24);
pf.setText("abcdefghijklmn");
pf.setAlignmentX(Component.RIGHT_ALIGNMENT);
AbstractDocument doc = (AbstractDocument) pf.getDocument();
doc.setDocumentFilter(new ASCIIOnlyDocumentFilter());

AbstractButton b = new JToggleButton(new AbstractAction() {
  @Override public void actionPerformed(ActionEvent e) {
    AbstractButton c = (AbstractButton) e.getSource();
    Character ec = c.isSelected() ? 0
        : (Character) UIManager.get("PasswordField.echoChar");
    pf.setEchoChar(ec);
    pf.setEchoChar(c.isSelected()
      ? '\u0000'
      : (Character) UIManager.get("PasswordField.echoChar"));
  }
});
b.setFocusable(false);
b.setOpaque(false);
b.setContentAreaFilled(false);
b.setBorder(BorderFactory.createEmptyBorder(0, 0, 0, 4));
b.setAlignmentX(Component.RIGHT_ALIGNMENT);
b.setAlignmentY(Component.CENTER_ALIGNMENT);
#spandel
b.setIcon(new ColorIcon(Color.GREEN));
#spanend
#spandel
b.setRolloverIcon(new ColorIcon(Color.BLUE));
#spanend
#spandel
b.setSelectedIcon(new ColorIcon(Color.RED));
#spanend
#spandel
b.setRolloverSelectedIcon(new ColorIcon(Color.ORANGE));
#spanend
#spanadd
b.setIcon(new EyeIcon(Color.BLUE));
#spanend
#spanadd
b.setRolloverIcon(new EyeIcon(Color.DARK_GRAY));
#spanend
#spanadd
b.setSelectedIcon(new EyeIcon(Color.BLUE));
#spanend
#spanadd
b.setRolloverSelectedIcon(new EyeIcon(Color.BLUE));
#spanend
#spanadd
b.setToolTipText("show/hide passwords");
#spanend

JPanel panel = new JPanel() {
  @Override public boolean isOptimizedDrawingEnabled() {
    return false;
  }
};
panel.setLayout(new OverlayLayout(panel));
panel.add(b);
panel.add(pf);
View in GitHub: Java, Kotlin

解説

上記のサンプルでは、JPasswordField#setEchoChar(...)メソッドの値に0を設定することで、パスワードを直接表示するように切り替えることのできるボタンを追加しています。

解説

上記のサンプルでは、JPasswordField#setEchoChar(...)メソッドの値に\u0000(0)を設定して入力したパスワードを可視状態に切り替えるためのボタンを追加しています。
  • 上: BorderLayoutで、JPasswordFieldの下にパスワード表示非表示切り替え用のJCheckBoxを配置
  • 下: OverlayLayoutで、JPasswordField内の右端にパスワード表示非表示切り替え用のJToggleButtonを配置
    • JPasswordFieldJToggleButtonを配置するJPanelに、OverlayLayoutを設定し、z軸が入れ替わらないように、JPanel#isOptimizedDrawingEnabled()が常にfalseを返すようオーバーライド
  • BorderLayout + JCheckBox:
    • BorderLayoutJPasswordFieldの下にパスワード表示非表示切り替え用のJCheckBoxを配置
  • OverlayLayout + JToggleButton:
    • OverlayLayoutJPasswordField内の右端にパスワード表示非表示切り替え用のJToggleButtonを配置
    • JPasswordFieldJToggleButtonを配置するJPanelOverlayLayoutを設定し、マウスカーソルでこのレイアウトのz軸が入れ替わらないようにJPanel#isOptimizedDrawingEnabled()が常にfalseを返すようオーバーライド
  • CardLayout + JTextField(can copy) + ...:
    • 同じDocumentを使用するJPasswordFieldJTextFieldCardLayoutを設定したJPanelを作成
    • OverlayLayoutを設定したJPanelに上記のJPanelJToggleButtonを配置し、JPasswordFieldなどの内部右端にボタンが表示されるように設定
    • JTextFieldをそのまま使用しているので表示中の文字列を選択してコピー可能
      #spanend
      #spanadd
      JPasswordField pf3 = new JPasswordField(24);
      #spanend
      #spanadd
      pf3.setText("abcdefghijklmn");
      #spanend
      #spanadd
      AbstractDocument doc = (AbstractDocument) pf3.getDocument();
      #spanend
      #spanadd
      JTextField tf3 = new JTextField(24);
      #spanend
      #spanadd
      tf3.setFont(FONT);
      #spanend
      #spanadd
      tf3.enableInputMethods(false);
      #spanend
      #spanadd
      tf3.setDocument(doc);
      #spanend
      
      ----
      #spandel
      `CardLayout`を使用するサンプルは、以下の理由で全面修正
      #spanend
      #spanadd
      final CardLayout cardLayout = new CardLayout();
      #spanend
      #spanadd
      final JPanel p3 = new JPanel(cardLayout);
      #spanend
      #spanadd
      p3.setAlignmentX(Component.RIGHT_ALIGNMENT);
      #spanend
      #spanadd
      p3.add(pf3, PasswordField.HIDE.toString());
      #spanend
      #spanadd
      p3.add(tf3, PasswordField.SHOW.toString());
      #spanend
      
      - [http://docs.oracle.com/javase/jp/8/api/javax/swing/JPasswordField.html#setEchoChar-char- JPasswordField#setEchoChar(...) (Java Platform SE 8)]に、「値0に設定すると、標準のJTextFieldの動作と同様に、テキストが入力したとおりに表示されます。」とあるように、`passwordField.setEchoChar((char) 0);`とすれば、`CardLayout`を使って、`JTextField`を表示させなくても、パスワードを表示することが可能
      #spanadd
      AbstractButton b3 = new JToggleButton(new AbstractAction() {
      #spanend
        @Override public void actionPerformed(ActionEvent e) {
          AbstractButton c = (AbstractButton) e.getSource();
          PasswordField s = c.isSelected() ? PasswordField.SHOW
                                           : PasswordField.HIDE;
          cardLayout.show(p3, s.toString());
        }
      #spanadd
      });
      #spanend
      #spanadd
      
  • press and hold down the mouse button:
    • OverlayLayoutJPasswordField内の右端にパスワード表示非表示切り替え用のJButtonを配置
    • このJButtonMouseListenerを追加してマウスでクリックしている間はパスワードを表示するように設定
      #spanend
      #spanadd
      b4.addMouseListener(new MouseAdapter() {
      #spanend
        @Override public void mousePressed(MouseEvent e) {
          pf4.setEchoChar('\u0000');
        }
        @Override public void mouseReleased(MouseEvent e) {
          pf4.setEchoChar((Character) UIManager.get("PasswordField.echoChar"));
        }
      #spanadd
      });
      #spanend
      #spanadd
      
  • 上: CardLayout
    • 同じDocumentを使用するJPasswordFieldJTextFieldCardLayoutを設定したJPanelに配置してJCheckBoxで切り替え
    • textField.enableInputMethods(false);として、インプットメソッドを使用不可に設定
  • 中: CardLayout + ASCII only filter
    • 同じDocumentを使用するJPasswordFieldJTextFieldCardLayoutを設定したJPanelに配置してJCheckBoxで切り替え
    • textField.enableInputMethods(false);として、インプットメソッドを使用不可に設定
    • ASCII以外の文字がコピー・ペーストなどできないようにするDocumentFilterを作成してDocumentに設定
  • 下: CardLayout + OverlayLayout
    • 同じDocumentを使用するJPasswordFieldJTextFieldCardLayoutを設定したJPanelを作成
    • OverlayLayoutを設定したJPanelに、上記のJPanelJToggleButtonを配置し、JPasswordFieldなどの内部右端にボタンが表示されるように設定
      • -
  • passwordField.setEchoChar((char) 0);を使用するサンプルを追加
    • JPasswordField#setEchoChar(...) (Java Platform SE 8)に「値0に設定すると標準のJTextFieldの動作と同様にテキストが入力したとおりに表示されます。」とあるようにpasswordField.setEchoChar((char) 0);とすればパスワード文字列の表示が可能
    • CardLayoutを使ってJTextFieldを表示する方法は一旦削除したが、表示中のパスワードをコピー可能なので残しておくことにした
  • ボタンをクリックしている間だけパスワードを表示するサンプルを追加

参考リンク

参考リンク

コメント

コメント