2013年9月13日 星期五

[ Java 代碼範本 ] 如何為 Java UI 添加 Key Listener

Preface: 
在平常我們常常使用 Windows 的 Ctrl+C (複製) , Ctrl+P (貼上) etc, 那我們有沒有辦法在 Java UI 上添加類似的快捷鍵呢? 答案是使用 KeyAdapter 類別. 底下我們透過一個簡單範例說明如何為 UI 添加快捷鍵與剪貼簿的使用. 

CalcUI 範例: 
考慮我們有個只有加法的 Calculator 如下, 在按下 "=" 按鈕後會將計算結果顯示於最右邊的 TextField: 
 

而如果我們要將計算結果取出, 則需要到最右邊的 TextField 選取所有內容後, 再按下 Ctrl+C 的複製快捷鍵. 但我們希望一旦按下 "=" 鍵, 接著直接按下 Ctrl+C 的快捷鍵便可以將計算結果置於剪貼簿中. 因此下面將說明如何完成這個需求. 

Step1. 第一步就是要先讓 UI 可以監聽到鍵盤的 Event, 此因我們新增另一個類別來處理 Key event 並監聽 Ctrl+C 的事件: 
  1. class MyKeyListener extends KeyAdapter{    
  2.     public void keyPressed(KeyEvent e){    
  3.         if ((e.getKeyCode() == KeyEvent.VK_C) && ((e.getModifiers() & KeyEvent.CTRL_MASK) != 0)) {  
  4.             // Copy calculation result to clipboard  
  5.            }  
  6.     }    
  7. }  
Step2. 接著為了要能操作 clipboard, 最外層的 JFrame 需要實作 ClipboardOwner 介面; 並加入剛剛建立的 KeyEvent 監聽類別建立的物件: 
  1. public class CalcUI extends JFrame implements ClipboardOwner{  
  2. ...  
  3.     public CalcUI() {  
  4.         super();  
  5.         initGUI();  
  6.         clipboard = Toolkit.getDefaultToolkit().getSystemClipboard();    
  7.         addKeyListener(new MyKeyListener());  
  8.         setFocusable(true); // 確保自己能得到 focus 已收到監聽事件  
  9.         frame = this// 方便後續 reference 到自己.  
  10.     }  
  11. ...  
  12. }  
Step3. 然後因為按下 "=" 按鈕後外面的 JFrame 會失去 focus (導致不能監聽鍵盤事件), 因此要稍作修改: 
  1. jButtonEq.addActionListener(new ActionListener() {  
  2.     public void actionPerformed(ActionEvent evt) {  
  3.         int sum = Integer.valueOf(jTextFieldA.getText()) + Integer.valueOf(jTextFieldB.getText());  
  4.         jTextFieldSum.setText(String.valueOf(sum));  
  5.         frame.requestFocus(); // 讓外面的 JFrame 獲得 focus 以繼續監聽事件  
  6.     }  
  7. });  
Step4. 最後修改原先的 MyKeyListener 讓使用者鍵入 Ctrl+C 後將計算結果置於剪貼簿: 
  1. class MyKeyListener extends KeyAdapter{    
  2.     public void keyPressed(KeyEvent e){    
  3.         if ((e.getKeyCode() == KeyEvent.VK_C) && ((e.getModifiers() & KeyEvent.CTRL_MASK) != 0)) {  
  4.             StringSelection contents = new StringSelection(jTextFieldSum.getText());  
  5.             clipboard.setContents(contents, frame);    
  6.            }  
  7.     }    
  8. }  
完整代碼如下: 
  1. package swing.demo;  
  2. import java.awt.Toolkit;  
  3. import java.awt.datatransfer.Clipboard;  
  4. import java.awt.datatransfer.ClipboardOwner;  
  5. import java.awt.datatransfer.StringSelection;  
  6. import java.awt.datatransfer.Transferable;  
  7. import java.awt.event.ActionEvent;  
  8. import java.awt.event.ActionListener;  
  9. import java.awt.event.KeyAdapter;  
  10. import java.awt.event.KeyEvent;  
  11.   
  12. import javax.swing.JButton;  
  13. import javax.swing.JFrame;  
  14. import javax.swing.JLabel;  
  15. import javax.swing.JTextField;  
  16. import javax.swing.SwingConstants;  
  17. import javax.swing.SwingUtilities;  
  18. import javax.swing.WindowConstants;  
  19.   
  20. public class CalcUI extends JFrame implements ClipboardOwner{  
  21.     private JTextField jTextFieldA;  
  22.     private JTextField jTextFieldSum;  
  23.     private JButton jButtonEq;  
  24.     private JTextField jTextFieldB;  
  25.     private JLabel jLabelPlus;  
  26.     public CalcUI frame;  
  27.     private Clipboard clipboard;    
  28.   
  29.     /** 
  30.     * Auto-generated main method to display this JFrame 
  31.     */  
  32.     public static void main(String[] args) {  
  33.         SwingUtilities.invokeLater(new Runnable() {  
  34.             public void run() {  
  35.                 CalcUI inst = new CalcUI();  
  36.                 inst.setLocationRelativeTo(null);  
  37.                 inst.setVisible(true);  
  38.             }  
  39.         });  
  40.     }  
  41.       
  42.     public CalcUI() {  
  43.         super();  
  44.         initGUI();  
  45.         clipboard = Toolkit.getDefaultToolkit().getSystemClipboard();    
  46.         addKeyListener(new MyKeyListener());  
  47.         setFocusable(true);  
  48.         frame = this;  
  49.     }  
  50.       
  51.     private void initGUI() {  
  52.         try {  
  53.             setDefaultCloseOperation(WindowConstants.DISPOSE_ON_CLOSE);  
  54.             getContentPane().setLayout(null);  
  55.             {  
  56.                 jTextFieldA = new JTextField();  
  57.                 getContentPane().add(jTextFieldA);  
  58.                 jTextFieldA.setText("10");  
  59.                 jTextFieldA.setBounds(12128324);  
  60.                 jTextFieldA.setHorizontalAlignment(SwingConstants.CENTER);  
  61.             }  
  62.             {  
  63.                 jLabelPlus = new JLabel();  
  64.                 getContentPane().add(jLabelPlus);  
  65.                 jLabelPlus.setText("+");  
  66.                 jLabelPlus.setBounds(101151717);  
  67.                 jLabelPlus.setFont(new java.awt.Font("Arial",1,12));  
  68.                 jLabelPlus.setHorizontalAlignment(SwingConstants.CENTER);  
  69.             }  
  70.             {  
  71.                 jTextFieldB = new JTextField();  
  72.                 getContentPane().add(jTextFieldB);  
  73.                 jTextFieldB.setText("10");  
  74.                 jTextFieldB.setBounds(125122024);  
  75.                 jTextFieldB.setSize(8324);  
  76.                 jTextFieldB.setHorizontalAlignment(SwingConstants.CENTER);  
  77.             }  
  78.             {  
  79.                 jButtonEq = new JButton();  
  80.                 getContentPane().add(jButtonEq);  
  81.                 jButtonEq.setText("=");  
  82.                 jButtonEq.setFocusable(false);  
  83.                 jButtonEq.setBounds(214124224);  
  84.                 jButtonEq.setFont(new java.awt.Font("Arial",1,12));  
  85.                 jButtonEq.addActionListener(new ActionListener() {  
  86.                     public void actionPerformed(ActionEvent evt) {  
  87.                         int sum = Integer.valueOf(jTextFieldA.getText()) + Integer.valueOf(jTextFieldB.getText());  
  88.                         jTextFieldSum.setText(String.valueOf(sum));  
  89.                         frame.requestFocus(); // 讓外面的 JFrame 獲得 focus 以繼續監聽事件  
  90.                     }  
  91.                 });  
  92.             }  
  93.             {  
  94.                 jTextFieldSum = new JTextField();  
  95.                 getContentPane().add(jTextFieldSum);  
  96.                 jTextFieldSum.setText("?");  
  97.                 jTextFieldSum.setBounds(2671210524);  
  98.                 jTextFieldSum.setHorizontalAlignment(SwingConstants.CENTER);  
  99.             }  
  100.             pack();  
  101.             this.setSize(40086);  
  102.         } catch (Exception e) {  
  103.             //add your error handling code here  
  104.             e.printStackTrace();  
  105.         }  
  106.     }  
  107.       
  108.     class MyKeyListener extends KeyAdapter{    
  109.         public void keyPressed(KeyEvent e){    
  110.             if ((e.getKeyCode() == KeyEvent.VK_C) && ((e.getModifiers() & KeyEvent.CTRL_MASK) != 0)) {  
  111.                 StringSelection contents = new StringSelection(jTextFieldSum.getText());  
  112.                 clipboard.setContents(contents, frame);    
  113.             }  
  114.         }    
  115.     }  
  116.   
  117.     @Override  
  118.     public void lostOwnership(Clipboard arg0, Transferable arg1) {}   
  119. }  
Supplement: 
[blog] java Gui 键盘监听事件 
[ Java 代碼範本 ] 用 java 設定、取用剪貼簿內容 
stackoverflow: Java detect CTRL+X key 
Java Tutorial : How to write key listener

沒有留言:

張貼留言

[Git 常見問題] error: The following untracked working tree files would be overwritten by merge

  Source From  Here 方案1: // x -----删除忽略文件已经对 git 来说不识别的文件 // d -----删除未被添加到 git 的路径中的文件 // f -----强制运行 #   git clean -d -fx 方案2: 今天在服务器上  gi...