JOptionPane для получения пароля - PullRequest
46 голосов
/ 16 января 2012

JOptionPane может использоваться для получения строковых входных данных от пользователя, но в моем случае я хочу отобразить поле пароля в showInputDialog.

Мне нужен ввод данных, заданных пользователемдолжен быть замаскирован и возвращаемое значение должно быть в char[].Мне нужно диалоговое окно с сообщением, полем пароля и двумя кнопками.Это может быть сделано?Спасибо.

Ответы [ 6 ]

63 голосов
/ 16 января 2012

Да, это возможно, используя JOptionPane.showOptionDialog().Как то так:

JPanel panel = new JPanel();
JLabel label = new JLabel("Enter a password:");
JPasswordField pass = new JPasswordField(10);
panel.add(label);
panel.add(pass);
String[] options = new String[]{"OK", "Cancel"};
int option = JOptionPane.showOptionDialog(null, panel, "The title",
                         JOptionPane.NO_OPTION, JOptionPane.PLAIN_MESSAGE,
                         null, options, options[1]);
if(option == 0) // pressing OK button
{
    char[] password = pass.getPassword();
    System.out.println("Your password is: " + new String(password));
}
38 голосов
/ 16 января 2012

Самое простое - использовать метод JOptionPane showConfirmDialog и передать ссылку на JPasswordField;Например,

JPasswordField pf = new JPasswordField();
int okCxl = JOptionPane.showConfirmDialog(null, pf, "Enter Password", JOptionPane.OK_CANCEL_OPTION, JOptionPane.PLAIN_MESSAGE);

if (okCxl == JOptionPane.OK_OPTION) {
  String password = new String(pf.getPassword());
  System.err.println("You entered: " + password);
}

Редактировать

Ниже приведен пример использования пользовательского JPanel для отображения сообщения вместе с JPasswordField.В последнем комментарии я также (на скорую руку) добавил код, позволяющий JPasswordField получить фокус при первом отображении диалогового окна.

public class PasswordPanel extends JPanel {
  private final JPasswordField passwordField = new JPasswordField(12);
  private boolean gainedFocusBefore;

  /**
   * "Hook" method that causes the JPasswordField to request focus the first time this method is called.
   */
  void gainedFocus() {
    if (!gainedFocusBefore) {
      gainedFocusBefore = true;
      passwordField.requestFocusInWindow();
    }
  }

  public PasswordPanel() {
    super(new FlowLayout());

    add(new JLabel("Password: "));
    add(passwordField);
  }

  public char[] getPassword() {
      return passwordField.getPassword();
  }

  public static void main(String[] args) {
      PasswordPanel pPnl = new PasswordPanel();
      JOptionPane op = new JOptionPane(pPnl, JOptionPane.OK_CANCEL_OPTION, JOptionPane.PLAIN_MESSAGE);

      JDialog dlg = op.createDialog("Who Goes There?");

      // Wire up FocusListener to ensure JPasswordField is able to request focus when the dialog is first shown.
      dlg.addWindowFocusListener(new WindowAdapter() {
        @Override
        public void windowGainedFocus(WindowEvent e) {
            pPnl.gainedFocus();
        }
      });

      if (op.getValue() != null && op.getValue().equals(JOptionPane.OK_OPTION)) {
          String password = new String(pPnl.getPassword());
          System.err.println("You entered: " + password);
      }
  }
}
4 голосов
/ 16 января 2012

Вы можете создать свой собственный диалог, который расширяет JDialog, и затем вы можете поместить в него все, что захотите.

3 голосов
/ 25 августа 2015

Этот диалог выглядит намного лучше, если вы сделаете

dlg.setVisible(true);

Без этого вы его вообще не увидите.

Также

pPnl.gainedFocus();

должно быть

pPnl.gainedFocus();

Кроме того, он прекрасно работает.Спасибо за код.Сэкономив мне время, работая с Swing.

Кроме того, если вы не хотите оставлять диалог запущенным в фоновом режиме каждый раз, когда открываете его, вам нужно будет закрыть его чем-то вроде

dlg.dispatchEvent(new WindowEvent(dlg, WindowEvent.WINDOW_CLOSING));
dlg.dispose(); // else java VM will wait for dialog to be disposed of (forever)
0 голосов
/ 17 марта 2019

Решение Котлина, основанное на ответе Адамски .

На этот раз без кнопок, которые фокусируются, просто введите пароль и нажмите Enter или Escape, чтобы отменить ввод:

class PasswordPanel : JPanel(FlowLayout()) {

    private val passwordField = JPasswordField(20)
    private var entered = false

    val enteredPassword
        get() = if (entered) String(passwordField.password) else ""

    init {
        add(JLabel("Password: "))
        add(passwordField)
        passwordField.setActionCommand("OK")
        passwordField.addActionListener {
            if (it.actionCommand == "OK") {
                entered = true

                // https://stackoverflow.com/a/51356151/1020871
                SwingUtilities.getWindowAncestor(it.source as JComponent)
                    .dispose()
            }
        }
    }

    private fun request(passwordIdentifier: String) = apply {
        JOptionPane.showOptionDialog(null, this@PasswordPanel,
            "Enter $passwordIdentifier",
            JOptionPane.DEFAULT_OPTION,
            JOptionPane.INFORMATION_MESSAGE,
            null, emptyArray(), null)
    }

    companion object {

        fun requestPassword(passwordIdentifier: String) = PasswordPanel()
            .request(passwordIdentifier)
            .enteredPassword
    }
}

Использование: PasswordPanel.requestPassword(passwordIdentifier)

0 голосов
/ 04 сентября 2018

Следующий класс является продолжением замечательного ответа Адамски :

package com.stackoverflow.swing;

import java.awt.Component;
import java.awt.Dimension;
import java.awt.FlowLayout;
import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;
import javax.swing.JDialog;
import javax.swing.JLabel;
import javax.swing.JOptionPane;
import javax.swing.JPanel;
import javax.swing.JPasswordField;

/**
 * Class that creates a panel with a password field. Extension of Adamski's class
 *
 * @author adamski https://stackoverflow.com/users/127479/adamski
 * @author agi-hammerthief https://stackoverflow.com/users/2225787/agi-hammerthief
 * @see https://stackoverflow.com/a/8881370/2225787
 */
public class PasswordPanel extends JPanel {

  private final JPasswordField JFieldPass;
  private JLabel JLblPass;
  private boolean gainedFocusBefore;

  /**
   * "Hook" method that causes the JPasswordField to request focus when method is
   * first  called.
   */
  public void gainedFocus () {
    if (!gainedFocusBefore) {
      gainedFocusBefore = true;
      JFieldPass.requestFocusInWindow();
    }
  }

  public PasswordPanel (int length) {
    super(new FlowLayout());
    gainedFocusBefore = false;
    JFieldPass = new JPasswordField(length);
    Dimension d = new Dimension();
    d.setSize(30, 22);
    JFieldPass.setMinimumSize(d);
    JFieldPass.setColumns(10);
    JLblPass = new JLabel("Password: ");
    add(JLblPass);
    add(JFieldPass);
  }

  public PasswordPanel() {
    super(new FlowLayout());
    gainedFocusBefore = false;
    JFieldPass = new JPasswordField();
    Dimension d = new Dimension();
    d.setSize(30, 22);
    JFieldPass.setMinimumSize(d);
    JFieldPass.setColumns(10);
    JLblPass = new JLabel("Password: ");
    add(JLblPass);
    add(JFieldPass);
  }

  public char[] getPassword() {
    return JFieldPass.getPassword();
  }

  public String getPasswordString() {
    StringBuilder passBuilder = new StringBuilder();

    char[] pwd = this.getPassword();
    if (pwd.length > 0) {
      for (char c : pwd) {
        passBuilder.append(c);
      }
    }

    return passBuilder.toString();
  }

  private static String displayDialog (
    Component parent, final PasswordPanel panel, String title
  ) {
    String password = null;
    /* For some reason, using `JOptionPane(panel, JOptionPane.OK_CANCEL_OPTION, JOptionPane.QUESTION_MESSAGE)`
    does not give the same results as setting values after creation, which is weird */
    JOptionPane op = new JOptionPane(panel);
    op.setMessageType(JOptionPane.QUESTION_MESSAGE);
    op.setOptionType(JOptionPane.OK_CANCEL_OPTION);
    JDialog dlg = op.createDialog(parent, title);
    // Ensure the JPasswordField is able to request focus when the dialog is first shown.
    dlg.addWindowFocusListener (new WindowAdapter () {
      @Override
      public void windowGainedFocus (WindowEvent e) {
        panel.gainedFocus ();
      }
    });
    dlg.setDefaultCloseOperation (JOptionPane.OK_OPTION); // necessary?

    dlg.setVisible (true);

    Object val = op.getValue ();
    if (null != val && val.equals (JOptionPane.OK_OPTION)) {
      password = panel.getPasswordString();
    }

    return password;
  }

  public static String showDialog (Component parent, String title) {
    final PasswordPanel pPnl = new PasswordPanel();
    return displayDialog(parent, pPnl, title);
  }

  public static String showDialog (
    Component parent, String title, int passwordLength
  ) {
    final PasswordPanel pPnl = new PasswordPanel(passwordLength);

    return displayDialog (parent, pPnl, title);
  }

  public static String showDialog (String title) {
    return showDialog(null, title);
  }

  public static String showDialog (String title, int passwordLength) {
    return showDialog(null, title, passwordLength);
  }

  /**
   * Show a test dialog
   */
  public static void main(String[] args) {
    String test = PasswordPanel.showDialog ("Enter Your Password");
    System.out.println ("Entered Password: " + test);
    System.exit(0);
  }

}
...