通过实现KeyBindings使用类型化的键 [英] Consume typed key by implements KeyBindings
问题描述
请帮助我如何将KeyBinding
和Consume
一起用于键入Chars
,与使用KeyListener
Can you please help me how to use KeyBinding
and with Consume
for typed Chars
together, same way as demostraded my SSCCE
by using KeyListener
import java.awt.*;
import java.awt.event.KeyEvent;
import java.awt.event.KeyListener;
import javax.swing.*;
public class Login {
private static final long serialVersionUID = 1L;
/* PassWord for unlock*/
private PswChecker checker = new PswChecker("pass");
public Login() {
JTextField firstField = new JTextField(10);
firstField.addKeyListener(passwordKeyListener);
JLabel firstLabel = new JLabel("Password is 'pass' ", JLabel.RIGHT);
firstLabel.setLabelFor(firstField);
JPanel p = new JPanel();
p.setLayout(new GridLayout(0, 2, 5, 5));
p.add(firstLabel);
p.add(firstField);
JFrame f = new JFrame("login");
f.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
f.setContentPane(p);
f.setLocationByPlatform(true);
f.pack();
f.setVisible(true);
}
//
private KeyListener passwordKeyListener = new KeyListener() {
private boolean enabled = true;
@Override
public void keyTyped(KeyEvent e) {
if (!enabled) {
return;
}
if (e.getKeyChar() != KeyEvent.CHAR_UNDEFINED) {
boolean b = checker.accept(e.getKeyChar());
e.consume();
if (b) {
enabled = false;
if (e.getComponent() != null) {
e.getComponent().removeKeyListener(this);
}
unlock();
}
}
}
@Override
public void keyReleased(KeyEvent e) {
}
@Override
public void keyPressed(KeyEvent e) {
}
};
void unlock() {
JOptionPane.showMessageDialog(null, "unlocked");
}
public static void main(String[] args) {
javax.swing.SwingUtilities.invokeLater(new Runnable() {
public void run() {
Login log = new Login();
}
});
}
class PswChecker {
private String password = null;
private boolean unlocked = false;
private long lastInputTimestamp = 0L;
private int index = 0;
public PswChecker(String password) {
if (password == null) {
throw new IllegalArgumentException("Null password");
}
if (password.trim().length() == 0) {
throw new IllegalArgumentException("Empty password");
}
this.password = password;
}
public boolean accept(char c) {
if (unlocked) {
return true;
}
long timestamp = System.currentTimeMillis();
if (timestamp - lastInputTimestamp > 700) {
index = 0;
}
lastInputTimestamp = timestamp;
if (password.charAt(index) == c) {
index++;
} else {
if (password.charAt(0) == c) {
index = 1;
} else {
index = 0;
}
}
unlocked = (index == password.length());
return unlocked;
}
public boolean isUnlocked() {
return unlocked;
}
public boolean isLocked() {
return !unlocked;
}
@Override
public String toString() {
return unlocked ? "UNLOCKED" : "LOCKED";
}
/*private boolean check(String keystrokes, String password, boolean expectUnLocked) {
PswChecker checker = new PswChecker(password);
for (int i = 0; i < keystrokes.length(); i++) {
checker.accept(keystrokes.charAt(i));
}
return checker.isUnlocked();
}*/
}
}
推荐答案
出于安全性考虑,请考虑此处所示.这将允许使用 DocumentFilter
,在此处中进行了讨论.
For security, consider JPasswordField
, illustrated here. This would allow use of a DocumentFilter
, discussed here.
附录:即使是更一般的情况,我也会使用 DocumentFilter
,如下所示.我会使用键绑定来共享Action
在各个组件之间,如此键盘示例所示.
Addendum: Even for the more general case, I'd use a DocumentFilter
, as shown below. I'd use key bindings for sharing an Action
among components, as shown in this keypad example.
附录:为了说明@kleopatra的评论,我更新了代码,将 ESC 绑定到Reset
.实际上,我只会使用尚未绑定到文本字段操作或正常使用所需的键.
Addendum: To illustrate @kleopatra's comment, I've updated the code to bind ESC to Reset
. As a practical matter, I'd use only keys that aren't already bound to text field actions or required for normal use.
import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.KeyEvent;
import javax.swing.*;
import javax.swing.text.*;
/** @see https://stackoverflow.com/q/9610386/230513 */
public class Login {
private static final String PWD = "pass";
private static final String RESET = "Reset";
private PlainDocument doc = new PlainDocument();
private JTextField text = new JTextField(doc, "", 10);
public Login() {
doc.setDocumentFilter(new FieldFilter(PWD));
JLabel label = new JLabel("Password is '" + PWD + "'", JLabel.RIGHT);
label.setLabelFor(text);
text.setToolTipText("Press ESC to reset.");
text.getInputMap().put(
KeyStroke.getKeyStroke(KeyEvent.VK_ESCAPE, 0), RESET);
text.getActionMap().put(RESET, new Reset());
JPanel p = new JPanel();
p.setLayout(new GridLayout(0, 2, 5, 5));
p.add(label);
p.add(text);
JFrame f = new JFrame("Login");
f.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
f.setContentPane(p);
f.setLocationByPlatform(true);
f.pack();
f.setVisible(true);
}
private static class FieldFilter extends DocumentFilter {
private String password;
private boolean unlocked;
private StringBuilder sb = new StringBuilder();
public FieldFilter(String password) {
this.password = password;
}
@Override
public void replace(FilterBypass fb, int offset, int length,
String text, AttributeSet attrs) throws BadLocationException {
if (unlocked) {
super.replace(fb, offset, length, text, attrs);
} else {
sb.append(text);
unlocked = password.equals(sb.toString());
}
}
public void reset() {
sb.delete(0, sb.length());
unlocked = false;
}
}
private static class Reset extends AbstractAction {
@Override
public void actionPerformed(ActionEvent e) {
JTextField jtf = (JTextField) e.getSource();
PlainDocument doc = (PlainDocument) jtf.getDocument();
try {
doc.remove(0, doc.getLength());
} catch (BadLocationException ex) {
ex.printStackTrace(System.err);
}
FieldFilter filter = (FieldFilter) doc.getDocumentFilter();
filter.reset();
}
}
public static void main(String[] args) {
javax.swing.SwingUtilities.invokeLater(new Runnable() {
@Override
public void run() {
Login log = new Login();
}
});
}
}
这篇关于通过实现KeyBindings使用类型化的键的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!