第一次聽說監聽是三年前,做一個webGIS的項目,當時對Listener的印象就是個“監視器”,監視着界面的一舉一動,一有動靜就觸發對應的響應。
一、概述
通過對界面的某一或某些操作添加監聽,可以自發地調用監聽函數/監聽類,對操作作出反應。舉個栗子:被監聽的操作是“你惹你媽生氣了”,添加的響應是“你媽給你爸打電話,你爸回家了,你爸打你一頓 ”。所以不管什么時候,只要“你惹你媽生氣了”,都會觸發這個操作的監聽,最終結果是每次你都會被你爸打一頓。屢試不爽,無一例外。這就是事件監聽,java.util.EventListener。
Listener分很多種:ActionListener,MouseListener,PopMenuListener,windowListener等等。
二、監聽事件實現方式
1. 直接在控件中添加監聽
如:給“保存按鈕”添加ActionListener監聽
1 saveCharaEditButton.addActionListener(new ActionListener() { 2 3 @Override 4 public void actionPerformed(ActionEvent e) { 5 // TODO Auto-generated method stub 6 save(); 7 } 8 });
2.寫一個監聽類,實現監聽接口。
添加事件監聽時只需要 添加這個監聽類就ok了。【PS:這個內部類與函數並列寫就可以,不用另建類文件,只是前面注意不要加public修飾符。默認只能有一個public類。】
1 public JPanel setRightPanel(){ 2 JPanel rightPanel = new JPanel(); 3 double[][] size = {{15,TableLayout.FILL,30,TableLayout.FILL,35},{10,30,10,TableLayout.FILL}}; 4 rightPanel.setLayout(new TableLayout(size)); 5 JButton saveCharaEditButton = new JButton("保存編輯"); 6 JButton enableCharaEditButton = new JButton("啟用編輯"); 7 rightPanel.add(enableCharaEditButton, "1,1"); 8 rightPanel.add(saveCharaEditButton, "3,1"); 9 rightPanel.add(setCharaJCTablePanel(), "0,3,4,3"); 10 saveCharaEditButton.addActionListener(new saveEditToFloodCharacterValueListener());//添加監聽 11 return rightPanel; 12 }
1 class saveEditToFloodCharacterValueListener implements ActionListener{ 2 3 @Override 4 public void actionPerformed(ActionEvent e) { 5 // TODO Auto-generated method stub 6 FloodCharacterValue floodCharacterValue = new FloodCharacterValue(); 7 floodCharacterValue = FloodCharacterValue.transFldPropToFloodCharacterValue(editCharaFldprop); 8 m_doc.m_floodExtractCharacterValue = floodCharacterValue; 9 } 10 }
3. 添加適配器,也可以實現監聽。(其實方法同1)
首先說一下適配器和監聽接口的不同:new一個監聽接口,需要重載該接口下面的所有方法,你刪除任何一個,都會報錯;但是適配器可以只重載你需要的那個方法。
以windowListener為例,給對話框dialog添加監聽addWindowListerner,然后監聽內容為窗口適配器WindowAdapter。對比如下:
(1)監聽接口【默認重載所有方法,功能需求單一時不推薦】
dialog.addWindowListener(new WindowListener() { @Override public void windowOpened(WindowEvent e) { // TODO Auto-generated method stub } @Override public void windowIconified(WindowEvent e) { // TODO Auto-generated method stub } @Override public void windowDeiconified(WindowEvent e) { // TODO Auto-generated method stub } @Override public void windowDeactivated(WindowEvent e) { // TODO Auto-generated method stub } @Override public void windowClosing(WindowEvent e) { // TODO Auto-generated method stub } @Override public void windowClosed(WindowEvent e) { // TODO Auto-generated method stub } @Override public void windowActivated(WindowEvent e) { // TODO Auto-generated method stub } });
(2)添加適配器【可以只重載需要的方法,功能單一時推薦】
1 dialog.addWindowListener(new WindowAdapter() { 2 @Override 3 public void windowClosed(WindowEvent e) { 4 // TODO Auto-generated method stub 5 JDialog dialog2 = (JDialog) e.getSource(); 6 set_infoSectionList(update_infoSectionListByProp(prop)); 7 if (basinCheckList != null && !basinCheckList.isEmpty() && basinCheckList.get(0).getCHECKED()==1) { 8 tableCharaShowPanel.updateData(schemeType, get_infoSectionList(), false); 9 }else { 10 tableCharaShowPanel.updateData(schemeType, get_infoSectionList(), true); 11 } 12 super.windowClosed(e); 13 dialog2.dispose(); 14 } 15 });
另外,關於添加哪些適配器,可以選擇WindowAdapter,右鍵菜單中選擇-resources-override/implement methods... - 勾選需要添加的方法即可。
4. 添加全局控件的監聽
背景:leftSecTypeList,rightSecTypeList,leftButton,rightButton 是this的全局控件變量。現在給他們添加鼠標點擊監聽.
這種操作一般分為兩步:
(1)在初始化該控件的時候,添加參數為this的鼠標監聽。
leftSecTypeList.addMouseListener(this);
(2)重寫mouseClicked(MouseEvent e)函數,根據e.getSource() 判斷是觸發鼠標點擊的是哪個控件,給出相應的反應。
1 public JPanel createSelPanel(){ 2 JPanel panel = new JPanel();
*** 22 leftSecTypeList.addMouseListener(this); 23 rightSecTypeList.addMouseListener(this); 24 leftButton.addMouseListener(this); 25 rightButton.addMouseListener(this); 26 return panel; 27 }
1 @Override 2 public void mouseClicked(MouseEvent e) { 3 // TODO Auto-generated method stub 4 Object sourceObject = e.getSource(); 5 if (sourceObject == leftSecTypeList&& e.getClickCount() == 2) { 6 HFSection section = leftSecTypeList.getSelectedItemType(); 9 }else if (sourceObject == rightSecTypeList&& e.getClickCount() == 2) { 10 HFSection section = rightSecTypeList.getSelectedItemType(); 11 }else if (sourceObject == leftButton) { 12 13 }else if (sourceObject == rightButton) { 14 15 } 16 }
5.利用類AbstractButton的set/get動作命令。
Abstract直接已知子類:JButton, JMenuItem, JToggleButton
void setActionCommand(String actionCommand)設置此按鈕的動作命令。
string getActionCommand() 返回此按鈕的動作命令。
//創建菜單Item的函數
private JMenuItem createMenuItem(String text,String actionCommand) { JMenuItem item = new JMenuItem(text); item.setActionCommand(actionCommand);//設置此按鈕的動作命令 item.addActionListener(new MenuActionListener()); return item; }
//創建菜單 private void initPopupMenu() { layerPopupMenu = new JPopupMenu(); layerPopupMenu.add(createMenuItem("添加目錄","addDir")); layerPopupMenu.add(createMenuItem("添加圖層","addLayer")); layerPopupMenu.addSeparator(); layerPopupMenu.add(createMenuItem("上移","up")); layerPopupMenu.add(createMenuItem("下移","down")); }
// 右鍵菜單操作命令 class MenuActionListener implements ActionListener { @Override public void actionPerformed(ActionEvent e) { String actionCommand = e.getActionCommand(); if(actionCommand.equals("addDir")){ addDir();} else if(actionCommand.equals("addLayer")){ addLayer();} else if(actionCommand.equals("up")){ layerUp();} else if(actionCommand.equals("down")){ layerDown();} }
6. 以接口實現對按鈕的監聽響應
1.在工具條面板中:(1)定義響應接口 (2)以接口定義響應變量 (3)定義按鈕,監聽響應為變量
2.在調用文件中: 以implents方式實現 工具條面板中對應的接口變量
//1-1 ControlBarPanel.java 定義接口 public interface IBackwardActionPerformed { public void ActionPerformed(ActionEvent e); } //1-2 ControlBarPanel.java 以接口定義響應變量 public IBackwardActionPerformed backwardActionPerformed; //1-3 ControlBarPanel.java 定義按鈕,監聽響應為變量 backwardButton.addActionListener(new ActionListener() { @Override public void actionPerformed(ActionEvent e) { // TODO Auto-generated method stub backwardActionPerformed.ActionPerformed(e); } }); //2-1 MainForcastPanel.java 實現響應變量具體操作 controlBarPanel.backwardActionPerformed = new BackwardBtnActionListener(); //2-2 MainForcastPanel.java 實現響應變量具體操作 class BackwardBtnActionListener implements IBackwardActionPerformed,Runnable { @Override public void ActionPerformed(ActionEvent e) { // TODO Auto-generated method stub Thread thread = new Thread(this); new HFProgressPane1(thread, "正在計算中......", null, null); } @Override public void run() { // TODO Auto-generated method stub ************ } }
3. 方法6的詳細代碼
1 public class ControlBarPanel extends JPanel implements ActionListener{ 2 private JButton jButton; 3 public IActionPerformed iActionPerformed; 4 5 public JPanel createPanel(){ 6 JPanel panel = new JPanel(); 7 panel.setLayout(new FlowLayout(FlowLayout.LEFT, 2, 0)); 8 jButton = new JButton("testButton"); 9 jButton.setMargin(new Insets(0, 0, 0, 0)); 10 jButton.addActionListener(new ActionListener() { 11 @Override 12 public void actionPerformed(ActionEvent e) { 13 // TODO Auto-generated method stub 14 iActionPerformed.ActionPerformed(e); 15 } 16 }); 17 panel.add(createForeTypePanel()); 18 panel.add(jButton); 19 return panel; 20 } 21 22 public interface IActionPerformed { 23 public void ActionPerformed(ActionEvent e); 24 } 25 } 26 27 public class ShowPanel extends JPanel { 28 private ControlBarPanel controlBarPanel; 29 //構造函數 30 public ShowPanel() { 31 controlBarPanel = new ControlBarPanel(); 32 controlBarPanel.iActionPerformed = new ActionListener(); 33 this.setLayout(new BorderLayout()); 34 this.add(controlBarPanel,BorderLayout.NORTH); 35 } 36 37 class ActionListener implements IActionPerformed{ 38 @Override 39 public void ActionPerformed(ActionEvent e) { 40 // TODO Auto-generated method stub 41 function(e); 42 } 43 } 44 }
7. 添加監聽列表,然后通知所有監聽。
分為三步
(1)定義變量:監聽列表
(2)定義函數:注冊監聽,刪除監聽
(3)定義函數:通知所有監聽
代碼如下:
1 /** 2 * 拖動完成后監聽保存隊列 3 */ 4 private List dragOverListenerList =new ArrayList(); 5 6 /** 7 * 注冊監聽事件 8 */ 9 public void addDragOverListener(DragOverListener listener){ 10 synchronized (objSync) { 11 dragOverListenerList.add(listener); 12 } 13 } 14 15 /** 16 * 刪除監聽 17 * @param eventObject 18 */ 19 public void removeDragOverListener(DragOverListener listener){ 20 synchronized (objSync) { 21 dragOverListenerList.remove(listener); 22 } 23 } 24 25 /** 26 * 通知所有監聽事件 27 */ 28 private void notifyAllListener(){ 29 for(int i=0;i<dragOverListenerList.size();i++) 30 { 31 ((DragOverListener)dragOverListenerList.get(i)).actionPerform(new DragOverEvent(this)); 32 } 33 } 34
在需要調用監聽的地方,添加通知監聽事件的函數即可。
四、小結
以上是一些Java事件監聽與使用方法的一些介紹,屬於入門級別。高級應用后期再予以學習與記錄。
寫於2017年1月6日
