Java Swing Action 動作


 Swing包提供了一種非常實用的機制來封裝命令,並將它們連接到多個事件源,這就是Action接口。一個動作是一個封裝下列內容的對象:

  × 命令的說明(一個文本字符串和一個可選圖標);

  × 執行命令所需要的參數(例如,在列舉的例子中請求改變的顏色)。

  Action接口包含下列內容:

 

[java]  view plain  copy
 
 print?
  1. public void actionPerformed(ActionEvent e);  
  2. public void setEnabled(boolean b);  
  3. public boolean isEnabled();  
  4. public void putValue(String key, Object value);  
  5. public Object getValue(String key);  
  6. public void addPropertyChangeListener(PropertyChangeListener listener);  
  7. public void removePropertyChangeListener(PropertyChangeListener listener);  


  actionPerformed方法是ActionListener接口中的一個:實際上,Action接口擴展於ActionListener接口,因此,可以在任何需要ActionListener對象的地方使用Action對象。

 

  setEnabled和isEnbaled兩個方法允許啟用或禁用這個動作,並檢查這個動作當前是否啟用。當一個連接到菜單或工具欄上的動作被禁用時,這個選項就會變成灰色。

  putValue和getValue兩個方法允許存儲和檢索動作對象中的任意名/值。有兩個重要的預定義字符串:Action.NAME和Action.SMALL_ICON,用於將動作的名字和圖標存儲到一個動作對象中:

[java]  view plain  copy
 
 print?
  1. action.putValue(Action.NAME,"Blue");  
  2. action.putValue(Action.SMALL_ICON,new ImageIcon("blue-ball.gif"));  

 表1給出了所有預定義的動作表名稱。

 

 

表1 預定義動作表名稱
名稱
NAME 動作名稱,顯示在按鈕和菜單上
SMALL_ICON 存儲小圖標的地方;顯示在按鈕、菜單項或工具欄中
SHORT_DESCRIPTION 圖標的簡要說明;顯示在工具提示中
LONG_DESCRIPTION 圖標的詳細說明;使用在在線幫助中。沒有Swing組件使用這個值
MNEMONIC_KEY 快捷鍵縮寫;顯示在菜單項中
ACCELERATOR_KEY 存儲加速擊鍵的地方;Swing組件不使用這個值
ACTION_COMMAND_KEY 歷史遺留;僅在舊版本的registerKeyboardAction方法中使用
DEFALUT 常用的綜合屬性;Swing組件不使用這個值

 

 

  如果動作對象添加到菜單或工具欄上,它的名稱和圖標就會被自動地提取出來,並顯示在菜單項或工具欄項中。SHORT_DESCRIPTION值變成了工具提示。

  addPropertyChangeListener和removePropertyChangeListener兩個方法能夠讓其他對象在動作對象的屬性發生變化時得到通告,尤其是菜單或工具欄觸發的動作。例如,如果增加一個菜單,作為動作對象的屬性變更監聽器,而這個動作對象愛你個隨后被禁用,菜單就會被調用,並將動作名稱變為灰色。屬性變更監聽器是一種常用的構造形式,它是JavaBeans組件模型的一部分。

  需要注意,Action是一個接口,而不是一個類。實現這個接口的所有類都必須實現剛才討論的7個方法。慶幸的是,有一個類實現了這個接口除actionPerformed方法之外的所有方法,它就是AbstractAction。這個類存儲了所有名/值對,並管理着屬性變更監聽器。我們可以直接擴展AbstractAction類,並在擴展類中實現actionPerformed方法。

  下面構造一個用於執行改變顏色命令的動作對象。首先存儲這個命令的名稱、圖標和需要的顏色。將顏色存儲在AbstractAction類提供的名/值對表中。下面是ColorAction類的代碼。構造器設置名/值對,而actionPerformed方法執行改變顏色的動作。

 

[java]  view plain  copy
 
 print?
  1. public class ColorAction extends AbstractAction  
  2. {  
  3.     public ColorAction(String name,Icon icon,Color c)  
  4.     {  
  5.         putValue(Action.NAME,name);  
  6.         putValue(Action.SMALL_ICON,icon);  
  7.         putValue(Action.SHORT_DESCRIPTION,"Set panel color to "+name.toLowerCase());  
  8.         putValue("color",c);  
  9.     }  
  10.       
  11.     public void actionPerformed(ActionEvent event)  
  12.     {  
  13.         Color c = (Color)getValue("color");  
  14.         buttonPanel.setBackground(c);  
  15.     }  
  16. }  


  在測試程序中,創建了三個這個類的對象,如下所示:

 

 

[java]  view plain  copy
 
 print?
  1. Action yellowAction = new ColorAction("Yellow",new ImageIcon("yellow-ball.gif"),Color.YELLOW);  
  2. Action blueAction = new ColorAction("Blue",new ImageIcon("blue-ball.gif"),Color.BLUE);  
  3. Action redAction = new ColorAction("Red",new ImageIcon("red-ball.gif"),Color.RED);  


  接下來,將這個動作與一個按鈕關聯起來。由於JButton有一個用Action對象作為參數的構造器,所以實現這項操作很容易。

 

 

[java]  view plain  copy
 
 print?
  1. buttonPanel.add(new JButton(yellowAction));          
  2. buttonPanel.add(new JButton(blueAction));  
  3. buttonPanel.add(new JButton(redAction));  

 

  構造器讀取動作的名稱和圖標,為工具提示設置簡要說明,將動作設置為監聽器。

  最后,想要將這個動作對象添加到擊鍵中,以便讓用戶敲擊鍵盤命令來執行這項動作。為了將動作與擊鍵關聯起來,首先需要生成KeyStroke類對象。這是一個很有用的類,它封裝了對鍵的說明。要想生成一個KeyStroke對象,不要調用構造器,而是調用KeyStroke類中的靜態getKeyStroke方法:

 

[java]  view plain  copy
 
 print?
  1. KeyStroke ctrlBKey = KeyStroke.getKeyStroke("ctrol B");   

  為了能夠理解下一個步驟,需要知道Keyborad focus的概念。用戶界面中可以包含許多按鈕、菜單、滾動欄以及其他的組件。當用戶敲擊鍵盤時,這個動作會被發送給擁有焦點的組件。通常具有焦點的組件可以明顯地察覺到(但並不總是這樣),例如,在Java觀感中,具有焦點的按鈕在按鈕文本周圍有一個細的矩形邊框。用戶可以使用TAB鍵在組件之間移動焦點。當按下SPACE鍵時,就點擊了擁有焦點的按鈕。還有一些鍵執行一些其他的動作,例如,按下箭頭鍵可以移動滾動條。

 

  然而,在這里的示例中,並不希望將擊鍵發送給擁有焦點的組件。否則,每個按鈕都需要知道如何處理CTRL+Y、CTRL+B和CTRL+R這些組合鍵。

  這是一個常見的問題,Swing設計者給出了一種很便捷的解決方案。每個JComponent有三個輸入映射(input maps),每一個映射的KeyStroke對象都與動作關聯。三個輸入映射對應着三個不同的條件。

 

表2 輸入映射條件
標志 激活條件
WHEN_FOCUSED 當這個組件擁有鍵盤焦點時
WHEN_ANCESTOR_OF_FOCUSED_COMPONENT 當這個組件包含了擁有鍵盤焦點的組件時
WHEN_IN_FOCUSED_WINDOW 當這個組件被包含在一個擁有鍵盤焦點組件的窗口中時

 

 

  擊鍵處理將按照下列順序檢查這些映射:

  1)檢查具有輸入焦點組件的WHEN_FOCUSED映射。如果這個擊鍵存在,將執行對應的動作。如果動作已啟用,則停止處理。

  2)從具有輸入焦點的組件開始,檢查其父組件的WHEN_ANCESTOR_OF_FOCUSED_COMPONENT映射。一旦找到擊鍵對應的映射,就執行對應的動作。如果動作已啟用,將停止處理。

  3)查看具有輸入焦點的窗口中的所有可視的和啟用的組件,這個擊鍵被注冊到WHEN_IN_FOCUSED_WINDOW映射中。給這些組件(按照擊鍵注冊的順序)一個執行對應動作的機會。一旦第一個啟用的動作被執行,就停止處理。如果一個擊鍵在多個WHEN_IN_FOCUSED_WINDOW映射中出現,這部分處理就可能會出現問題。

  可以使用getInputMap方法從組件中得到輸入映射。例如:

 

[java]  view plain  copy
 
 print?
  1. InputMap imap = buttonPanel.getInputMap(JComponent.WHEN_FOCUSED);  

  WHEN_FOCUSED條件意味着在當前組件擁有鍵盤焦點時會查看這個映射。在這里的示例中,並不想使用這個映射。是某個按鈕擁有輸入焦點,而不是面板。其他的兩個映射都能夠很好地完成增加顏色改變擊鍵的任務。在示例程序中使用的是WHEN_ANCESTOR_OF_FOCUSED_COMPONENT。

 

  InputMap不能直接地將KeyStroke對象映射到Action對象。而是先映射到任意對象上,然后由ActionMap類實現將對象映射到動作上的第2個映射。這樣很容易實現來自不同輸入映射的擊鍵共享一個動作的目地。

  因而,每個組件都可以有三個輸入映射和一個動作映射。為了將它們組合起來,需要為動作命名。下面是將鍵與動作關聯起來的方式:

 

[java]  view plain  copy
 
 print?
  1. imap.put(KeyStroke.getKeyStroke("ctrl Y"), "panel.yellow");  
  2. ActionMap amap = buttonPanel.getActionMap();  
  3. amap.put("panel.yellow",yellowAction);  


  習慣上,使用字符串none表示空動作。這樣可以輕松地取消一個鍵動作:

 

 

[java]  view plain  copy
 
 print?
  1. imap.put(KeyStroke.getKeyStroke("ctrl C"),"none");  

  警告:JDK文檔提倡使用動作名作為動作鍵。我們並不認為這是一個好建議。在按鈕和菜單項上顯示的動作名,UI設計者可以隨心所欲地進行更改,也可以將其翻譯成多種語言。使用這種不牢靠的字符串作為查詢鍵不是一種好的選擇。建議將動作名與現實的名字分開。

 

  下面總結一下用同一個動作響應按鈕、菜單項或擊鍵的方式:

  1)實現一個擴展於AbstractAction類的類。多個相關的動作可以使用同一個類。

  2)構造一個動作類的對象。

  3)使用動作對象創建按鈕或菜單項。構造器將從動作對象中讀取標簽文本和圖標。

  4)為了能夠通過擊鍵觸發動作,必須額外地執行幾步操作。首先定位頂層窗口組件,例如,包含所有其他組件的面板。

  5)然后,得到頂層組件的WHEN_ANCESTOR_OF_FOCUS_COMPONENT輸入映射。為需要的擊鍵創建一個KeyStrike對象。創建一個描述動作字符串這樣的動作鍵對象。將(擊鍵、動作鍵)對添加到輸入映射中。

  6)最后,得到頂層組件的動作映射。將(動作鍵,動作對象)添加到映射中。

  將按鈕和擊鍵映射到動作對象的完整程序代碼如下:

 

[java]  view plain  copy
 
 print?
  1. import java.awt.*;  
  2. import java.awt.event.*;  
  3. import javax.swing.*;  
  4.   
  5. public class ActionTest {  
  6.   
  7.     public static void main(String[] args) {  
  8.         EventQueue.invokeLater(new Runnable() {  
  9.   
  10.             public void run() {  
  11.                 ActionFrame frame = new ActionFrame();  
  12.                 frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);  
  13.                 frame.setVisible(true);  
  14.             }  
  15.         });  
  16.     }  
  17. }  
  18.   
  19. class ActionFrame extends JFrame {  
  20.   
  21.     public ActionFrame() {  
  22.         setTitle("ActionTest");  
  23.         setSize(DEFAULT_WIDTH, DEFAULT_HEIGHT);  
  24.   
  25.         buttonPanel = new JPanel();  
  26.   
  27.         // define actions  
  28.         Action yellowAction = new ColorAction("Yellow", new ImageIcon("yellow-ball.gif"), Color.YELLOW);  
  29.         Action blueAction = new ColorAction("Blue", new ImageIcon("blue-ball.gif"), Color.BLUE);  
  30.         Action redAction = new ColorAction("Red", new ImageIcon("red-ball.gif"), Color.RED);  
  31.   
  32.         // add buttons for these actions  
  33.         buttonPanel.add(new JButton(yellowAction));  
  34.         buttonPanel.add(new JButton(blueAction));  
  35.         buttonPanel.add(new JButton(redAction));  
  36.   
  37.         // add panel to frame  
  38.         add(buttonPanel);  
  39.   
  40.         // associate the Y, B, and R keys with names  
  41.         InputMap imap = buttonPanel.getInputMap(JComponent.WHEN_ANCESTOR_OF_FOCUSED_COMPONENT);  
  42.         imap.put(KeyStroke.getKeyStroke("ctrl Y"), "panel.yellow");  
  43.         imap.put(KeyStroke.getKeyStroke("ctrl B"), "panel.blue");  
  44.         imap.put(KeyStroke.getKeyStroke("ctrl R"), "panel.red");  
  45.   
  46.         // associate the names with actions  
  47.         ActionMap amap = buttonPanel.getActionMap();  
  48.         amap.put("panel.yellow", yellowAction);  
  49.         amap.put("panel.blue", blueAction);  
  50.         amap.put("panel.red", redAction);  
  51.     }  
  52.   
  53.     public class ColorAction extends AbstractAction {  
  54.   
  55.         public ColorAction(String name, Icon icon, Color c) {  
  56.             putValue(Action.NAME, name);  
  57.             putValue(Action.SMALL_ICON, icon);  
  58.             putValue(Action.SHORT_DESCRIPTION, "Set panel color to " + name.toLowerCase());  
  59.             putValue("color", c);  
  60.         }  
  61.   
  62.         public void actionPerformed(ActionEvent event) {  
  63.             Color c = (Color) getValue("color");  
  64.             buttonPanel.setBackground(c);  
  65.         }  
  66.     }  
  67.     private JPanel buttonPanel;  
  68.     public static final int DEFAULT_WIDTH = 300;  
  69.     public static final int DEFAULT_HEIGHT = 200;  
  70. }  


結果顯示:

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM