【发布时间】:2012-02-11 11:09:54
【问题描述】:
JOptionPane 可用于从用户获取字符串输入,但就我而言,我想在showInputDialog 中显示密码字段。
我需要的方式是屏蔽用户输入的内容,返回值必须在char[]。我需要一个带有消息、密码字段和两个按钮的对话框。可以这样做吗?谢谢。
【问题讨论】:
标签: java swing user-interface passwords joptionpane
JOptionPane 可用于从用户获取字符串输入,但就我而言,我想在showInputDialog 中显示密码字段。
我需要的方式是屏蔽用户输入的内容,返回值必须在char[]。我需要一个带有消息、密码字段和两个按钮的对话框。可以这样做吗?谢谢。
【问题讨论】:
标签: java swing user-interface passwords joptionpane
您可以创建自己的扩展 JDialog 的对话框,然后您可以在其中放入任何您想要的内容。
【讨论】:
是的,可以使用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));
}
【讨论】:
最简单的方法是使用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);
}
}
}
【讨论】:
如果你这样做,这个对话看起来会好很多
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)
【讨论】:
以下类是Adamski's great answer的扩展:
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);
}
}
【讨论】:
基于Adamski's answer 的 Kotlin 解决方案。
这次没有焦点按钮,只需输入密码并按 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)
【讨论】:
尝试在@Adamski和@Peter West的原始解决方案之后简化代码。
所有的接线都在PasswordPanel类中完成,客户端只调用静态getPassword方法。
String passwordText = PasswordPanel.getPassword();
if (null != passwordText) {
System.out.println("password: <" + passwordText + ">");
}
来源:
import javax.swing.*;
import java.awt.*;
import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;
public class PasswordPanel extends JPanel {
private final String password;
private PasswordPanel(String prompt) {
super(new FlowLayout());
JPasswordField pwdField = new JPasswordField(12);
add(pwdField);
JOptionPane joptionPane = new JOptionPane(this, JOptionPane.PLAIN_MESSAGE, JOptionPane.OK_CANCEL_OPTION);
boolean responseOK = configure(joptionPane, prompt, pwdField).equals(JOptionPane.OK_OPTION);
this.password = responseOK ? String.valueOf(pwdField.getPassword()) : null;
}
public static String getPassword(){
return new PasswordPanel("Input Password ... ").password;
}
private Object configure(JOptionPane jOptionPane, String prompt, JComponent pwdField) {
JDialog jDialog = promptDialog(prompt, jOptionPane, pwdField);
Object result = jOptionPane.getValue();
jDialog.dispatchEvent(new WindowEvent(jDialog, WindowEvent.WINDOW_CLOSING));
jDialog.dispose();
return result;
}
private JDialog promptDialog(String message, JOptionPane jOptionPane, JComponent pwdField) {
JDialog dialog = jOptionPane.createDialog(message);
dialog.addWindowFocusListener(new WindowAdapter() {
@Override
public void windowGainedFocus(WindowEvent e) {
pwdField.requestFocusInWindow();
}
});
dialog.setVisible(true);
return dialog;
}
}
【讨论】: