2012-03-07 25 views
1

能否請你幫我如何使用KeyBindingConsume的類型Chars在一起,相同的方式,demostraded我SSCCE使用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(); 
     }*/ 
    } 
} 
+0

+1這只是一個例子,還是應該使用'JPasswordField'? – trashgod 2012-03-08 00:51:04

+0

@trashgod對我的問題不是關於JPasswordField,關於從KeyBindings消耗事件, – mKorbel 2012-03-08 07:10:33

+0

如果它不是一個密碼,它是什麼?你到底想要什麼? – kleopatra 2012-03-08 11:10:26

回答

3

出於安全考慮JPasswordField,說明here 。這將允許使用DocumentFilter,討論here

附錄:即使是更一般的情況,我會使用DocumentFilter,如下所示。我將使用key bindings在組件之間共享Action,如此keypad example中所示。

附錄:爲了說明@ kleopatra的評論,我更新了代碼以將ESC更改爲Reset。實際上,我只使用那些尚未綁定到文本字段操作或正常使用所需的密鑰。

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(); 
      } 
     }); 
    } 
} 
+0

偉大的,很好,謝謝(以前)up_voted +1,請道歉,我的目標是明白如何KeyBindings的工作原理:-( – mKorbel 2012-03-08 13:25:51

+1

@mKorbel底層的keyEvent消費,如果a)在任何inputMaps找到綁定搜索和b)綁定動作已啓用 – kleopatra 2012-03-08 13:29:16

+0

@kleopatra這兩個方法對於KeyBindings的基本功能是必需的,您是否在談論將監聽器移動到第一個父節點(JPanel o r ...)和從Action分發所需的事件到(在這種情況下鍵盤鍵入的字符)JTextField或我錯了, – mKorbel 2012-03-08 13:38:33