201771010134楊其菊《面向物件程式設計(java)》第十三週學習總結
第十三週學習總結
第一部分:理論知識
第11章 事件處理(事件處理基礎; 動作; 滑鼠事件;AWT事件繼承層次)
1. 事件源(event source):能夠產生事件的物件都可 以成為事件源,如文字框、按鈕等。一個事件源是一個 能夠註冊監聽器並向監聽器傳送事件物件的物件。
2. 事件監聽器(event listener):事件監聽器物件接 收事件源傳送的通告(事件物件),並對發生的事件作 出響應。一個監聽器物件就是一個實現了專門監聽器接 口的類例項,該類必須實現介面中的方法,這些方法當 事件發生時,被自動執行。
3. 事件物件(event object):Java將事件的相關資訊 封裝在一個事件物件中,所有的事件物件都最終派生於 java.util.EventObject類。不同的事件源可以產生不 同類別的事件
4.AWT事件處理機制的概要:
(1) 監聽器物件:是一個實現了特定監聽器介面( listener interface)的類例項。
(2)事件源:是一個能夠註冊監聽器物件併發送事件對 象的物件。
(3)當事件發生時,事件源將事件物件自動傳遞給所 有註冊的監聽器。
(4) 監聽器物件利用事件物件中的資訊決定如何對事 件做出響應。
5.GUI設計中,程式設計師需要對元件的某種事件進行響應和處理時,必須完成兩個步驟:
(1) 定義實現某事件監聽器介面的事件監聽器類,並具體化介面中宣告的事件處理抽象方法。
(2) 為元件註冊實現了規定介面的事件監聽器物件;
6.註冊監聽器方法 eventSourceObject.addEventListener(eventListenerObject)
下面是監聽器的一個示例: ActionListener listener = …;
JButton button=new JButton(“Ok”); button.addActionListener(listener);
7.動作事件(ActionEvent):當特定元件動作(點 擊按鈕)發生時,該元件生成此動作事件。
(1) 該 事 件 被 傳 遞 給 組 件 注 冊 的 每 一 個 ActionListener 物件, 並 調 用 監 聽 器 對 象 的 actionPerformed方法以接收這類事件物件。
(2)能夠觸發動作事件的動作,主要包括:
1) 點選按鈕
2) 雙擊一個列表中的選項;
3) 選擇選單項;
4) 在文字框中輸入回車。
8. 監聽器介面的實現
監聽器類必須實現與事件源相對應的介面,即必須提供介面中方法的實現。
⚫ 監聽器介面方法實現
class Mylistener implements ActionListener
{
public void actionPerformed (ActionEvent event)
{ …… }
}
9.命令按鈕Jbutton主要API
a.建立按鈕物件
JButton類常用的一組構造方法:
(1) JButton(String text):建立一個帶文字的按鈕。
(2) JButton(Icon icon) :建立一個帶圖示的按鈕。
(3)JButton(String text, Icon icon) :建立一個帶文字和圖示
的按鈕。
b.按鈕物件的常用方法
① getLabel( ):返回按鈕的標籤字串;
② setLabel(String s):設定按鈕的標籤為字串s。
10. 用匿名類、lambda表示式簡化程式
例ButtonTest.java中,各按鈕需要同樣的處理:
1) 使用字串構造按鈕物件;
2) 把按鈕新增到面板上;
3) 用對應的顏色構造一個動作監聽器;
4) 註冊動作監聽器。
11.介面卡類
12.用匿名類簡化
13.動作事件
14.滑鼠事件
第二部分:實驗部分
實驗十三 圖形介面事件處理技術
實驗時間 2018-11-22
1、實驗目的與要求
(1) 掌握事件處理的基本原理,理解其用途;
(2) 掌握AWT事件模型的工作機制;
(3) 掌握事件處理的基本程式設計模型;
(4) 瞭解GUI介面元件觀感設定方法;
(5) 掌握WindowAdapter類、AbstractAction類的用法;
(6) 掌握GUI程式中滑鼠事件處理技術。
2、實驗內容和步驟
實驗1: 匯入第11章示例程式,測試程式並進行程式碼註釋。
測試程式1:
l 在elipse IDE中除錯執行教材443頁-444頁程式11-1,結合程式執行結果理解程式;
l 在事件處理相關程式碼處添加註釋;
l 用lambda表示式簡化程式;
l 掌握JButton元件的基本API;
l 掌握Java中事件處理的基本程式設計模型。
package First; import java.awt.*; import javax.swing.*; /** * @version 1.34 2015-06-12 * @author Cay Horstmann */ public class ButtonTest { public static void main(String[] args) { EventQueue.invokeLater(() -> { JFrame frame = new ButtonFrame();//建立物件;超類量引用子類物件; frame.setTitle("ButtonTest");//程式/軟體的名字 frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);//設定關閉操作; frame.setVisible(true);//使介面視覺化; }); } }
1 package First; 2 3 import java.awt.*; 4 import java.awt.event.*; 5 import javax.swing.*; 6 7 /** 8 * A frame with a button panel 9 */ 10 public class ButtonFrame extends JFrame { 11 private JPanel buttonPanel; 12 private static final int DEFAULT_WIDTH = 300*2; 13 private static final int DEFAULT_HEIGHT = 200*2; 14 15 public ButtonFrame() { 16 setSize(DEFAULT_WIDTH, DEFAULT_HEIGHT); 17 buttonPanel = new JPanel(); 18 makeButton("黃色", Color.yellow); 19 makeButton("藍色", Color.blue); 20 makeButton("紅色", Color.red); 21 makeButton("綠色",Color.green); 22 //新增面板到框架裡 23 add(buttonPanel); 24 25 } 26 27 protected void makeButton(String name,Color backgound) { 28 // 建立按鈕 29 JButton button = new JButton(name); 30 // //把按鈕新增到面板上 31 buttonPanel.add(button); 32 // create button actions 33 //方法一:通過內部類方式實現 34 /* 35 //構造一個物件,並將物件設定為按鈕監聽器 36 ColorAction action = new ColorAction(backgound); 37 // 為按鈕新增監聽器 38 button.addActionListener(action);*/ 39 //方法二:匿名內部類方式實現 40 /*button.addActionListener(new ActionListener() { 41 42 @Override 43 public void actionPerformed(ActionEvent e) { 44 // TODO 自動生成的方法存根 45 buttonPanel.setBackground(backgound); 46 } 47 });*/ 48 //方法三通過lambad表示式實現 49 button.addActionListener((e)->{ 50 buttonPanel.setBackground(backgound); 51 }); 52 53 } 54 55 /** 56 * An action listener that sets the panel's background color. 57 */ 58 //這是實現了 ActionListener介面的內部類 59 /*private class ColorAction implements ActionListener { 60 private Color backgroundColor; 61 62 public ColorAction(Color c) { 63 backgroundColor = c; 64 } 65 //實現ActionListener介面,監聽器類必須有一個actionPerformed方法 66 public void actionPerformed(ActionEvent event) { 67 buttonPanel.setBackground(backgroundColor); 68 } 69 }*/ 70 }
測試程式2:
l 在elipse IDE中除錯執行教材449頁程式11-2,結合程式執行結果理解程式;
l 在元件觀感設定程式碼處添加註釋;
l 瞭解GUI程式中觀感的設定方法。
1 package Second; 2 3 import java.awt.*; 4 import javax.swing.*; 5 6 /** 7 * @version 1.32 2015-06-12 8 * @author Cay Horstmann 9 */ 10 public class PlafTest 11 { 12 public static void main(String[] args) 13 { 14 EventQueue.invokeLater(() -> { 15 JFrame frame = new PlafFrame(); 16 frame.setTitle("PlafTest"); 17 frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); 18 frame.setVisible(true); 19 }); 20 } 21 }
1 package Second; 2 3 import javax.swing.JButton; 4 import javax.swing.JFrame; 5 import javax.swing.JPanel; 6 import javax.swing.SwingUtilities; 7 import javax.swing.UIManager; 8 9 /** 10 * A frame with a button panel for changing look-and-feel 11 */ 12 public class PlafFrame extends JFrame 13 { 14 private JPanel buttonPanel; 15 16 public PlafFrame() 17 { 18 buttonPanel = new JPanel(); 19 //獲取所有安裝的觀感實現 20 21 UIManager.LookAndFeelInfo[] infos = UIManager.getInstalledLookAndFeels(); 22 for (UIManager.LookAndFeelInfo info : infos) 23 makeButton(info.getName(), info.getClassName()); 24 25 add(buttonPanel); 26 pack(); 27 } 28 29 /** 30 * Makes a button to change the pluggable look-and-feel. 31 * @param name the button name 32 * @param className the name of the look-and-feel class 33 */ 34 private void makeButton(String name, String className) 35 { 36 // 向面板新增按鈕; 37 38 JButton button = new JButton(name); 39 buttonPanel.add(button); 40 41 // 設定按鈕動作; 42 43 button.addActionListener(event -> { 44 // 按鈕動作:切換到新的外觀和感覺 45 try 46 { 47 UIManager.setLookAndFeel(className); 48 //呼叫靜態方法,重新整理全部的元件集。這裡需要向方法提供一個元件,並由此找到其他的所有元件 49 //外部物件的this引用必須將外部類名作為字首 50 51 SwingUtilities.updateComponentTreeUI(this); 52 pack(); 53 } 54 catch (Exception e) 55 { 56 e.printStackTrace(); 57 } 58 }); 59 } 60 }
總結:預設情況下,Swing程式使用Metal觀感,可以採用兩種方式改變觀感。
- (沒有成功)在Java安裝的子目錄jre/lib下有一個檔案swing.properties.在這個檔案中,將swing.defaultlaf設定為所希望的觀感類名,如
swing.defaultlaf=com.sun.java.swing.plaf.motif.MotifLookAndFeel
。注意,Metal觀感位於javax.swing包中。其他的觀感包位於com.sun.java包中,並且不是在每個Java實現中都提供。 - 動態地改變觀感。這需要呼叫靜態的UIManager.setLookAndFeel方法,並提供所想要的觀感類名,然後再呼叫靜態方法SwingUtilities.updateComponentTreeUI重新整理全部的元件集。
測試程式3:
l 在elipse IDE中除錯執行教材457頁-458頁程式11-3,結合程式執行結果理解程式;
l 掌握AbstractAction類及其動作物件;
l 掌握GUI程式中按鈕、鍵盤動作對映到動作物件的方法。
1 package Third; 2 3 import java.awt.*; 4 import javax.swing.*; 5 6 /** 7 * @version 1.34 2015-06-12 8 * @author Cay Horstmann 9 */ 10 public class ActionTest 11 { 12 public static void main(String[] args) 13 { 14 EventQueue.invokeLater(() -> { 15 JFrame frame = new ActionFrame(); 16 frame.setTitle("ActionTest"); 17 frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); 18 frame.setVisible(true); 19 }); 20 } 21 }
1 package Third; 2 3 import java.awt.*; 4 import java.awt.event.*; 5 import javax.swing.*; 6 7 /** 8 * A frame with a panel that demonstrates color change actions. 9 */ 10 public class ActionFrame extends JFrame 11 { 12 private JPanel buttonPanel; 13 private static final int DEFAULT_WIDTH = 300; 14 private static final int DEFAULT_HEIGHT = 200; 15 16 public ActionFrame() 17 { 18 setSize(DEFAULT_WIDTH, DEFAULT_HEIGHT); 19 20 buttonPanel = new JPanel(); 21 22 // define actions 23 Action yellowAction = new ColorAction("Yellow", new ImageIcon("yellow-ball.gif"), 24 Color.YELLOW); 25 Action blueAction = new ColorAction("Blue", new ImageIcon("blue-ball.gif"), Color.BLUE); 26 Action redAction = new ColorAction("Red", new ImageIcon("red-ball.gif"), Color.RED); 27 28 //用Action物件構造按鈕,把動作和按鈕關聯起來 29 30 buttonPanel.add(new JButton(yellowAction)); 31 buttonPanel.add(new JButton(blueAction)); 32 buttonPanel.add(new JButton(redAction)); 33 34 // add panel to frame 35 add(buttonPanel); 36 37 //得到頂層元件的WHEN_ANCESTOR_OF_FOCUSED_COMPONENT輸入對映 38 39 // associate the Y, B, and R keys with names 40 InputMap imap = buttonPanel.getInputMap(JComponent.WHEN_ANCESTOR_OF_FOCUSED_COMPONENT); 41 //將(按鍵,動作鍵)新增到輸入對映中 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 //得到頂層元件的動作對映 48 ActionMap amap = buttonPanel.getActionMap(); 49 //將(動作鍵,動作物件)新增到對映中 50 51 amap.put("panel.yellow", yellowAction); 52 amap.put("panel.blue", blueAction); 53 amap.put("panel.red", redAction); 54 } 55 56 public class ColorAction extends AbstractAction 57 { 58 /** 59 * Constructs a color action. 60 * @param name the name to show on the button 61 * @param icon the icon to display on the button 62 * @param c the background color 63 */ 64 public ColorAction(String name, Icon icon, Color c) 65 { 66 //儲存命令的名稱、圖示、簡要說明和需要的顏色 67 putValue(Action.NAME, name); 68 putValue(Action.SMALL_ICON, icon); 69 putValue(Action.SHORT_DESCRIPTION, "Set panel color to " + name.toLowerCase());//顯示在工具提示裡 70 71 putValue("color", c); 72 } 73 74 public void actionPerformed(ActionEvent event) 75 { 76 Color c = (Color) getValue("color"); 77 buttonPanel.setBackground(c); 78 } 79 } 80 }
總結:用同一個動作相應按鈕、選單項或按鍵
- 實現一個擴充套件於AbstractAction類的類。多個相關的動作可以使用同一個類。
- 構造一個動作類的物件。
- 使用動作物件建立按鈕或選單項。構造器將從動作物件中讀取標籤文字和圖示。
- 為了能夠通過按鍵觸發動作,必須額外地執行幾步操作。首先定位頂層視窗元件,如包含所有其他元件的面板。
- 然後得到頂層元件的WHEN_ANCESTOR_OF_FOCUSED_COMPONENT輸入對映。為需要的按鍵建立一個KeyStroke物件。建立一個描述動作字串這樣的動作鍵物件。將(按鍵,動作鍵)對新增到輸入對映中。
- 最後,得到頂層元件的動作對映。將(動作鍵,動作物件)新增到對映中。
測試程式4:
l 在elipse IDE中除錯執行教材462頁程式11-4、11-5,結合程式執行結果理解程式;
l 掌握GUI程式中滑鼠事件處理技術。
1 package Forth; 2 3 import java.awt.*; 4 import javax.swing.*; 5 6 /** 7 * @version 1.34 2015-06-12 8 * @author Cay Horstmann 9 */ 10 public class MouseTest 11 { 12 public static void main(String[] args) 13 { 14 EventQueue.invokeLater(() -> { 15 JFrame frame = new MouseFrame(); 16 frame.setTitle("MouseTest"); 17 frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); 18 frame.setVisible(true); 19 }); 20 } 21 }
1 package Forth; 2 3 import javax.swing.*; 4 5 /** 6 * A frame containing a panel for testing mouse operations 7 */ 8 public class MouseFrame extends JFrame 9 { 10 public MouseFrame() 11 { 12 add(new MouseComponent()); 13 pack(); 14 } 15 }
1 package Forth; 2 3 import java.awt.*; 4 import java.awt.event.*; 5 import java.awt.geom.*; 6 import java.util.*; 7 import javax.swing.*; 8 9 /** 10 * A component with mouse operations for adding and removing squares. 11 */ 12 public class MouseComponent extends JComponent 13 { 14 private static final int DEFAULT_WIDTH = 300; 15 private static final int DEFAULT_HEIGHT = 200; 16 17 private static final int SIDELENGTH = 10; 18 private ArrayList<Rectangle2D> squares; 19 private Rectangle2D current; // the square containing the mouse cursor 20 21 public MouseComponent() 22 { 23 squares = new ArrayList<>(); 24 current = null; 25 26 addMouseListener(new MouseHandler()); 27 addMouseMotionListener(new MouseMotionHandler()); 28 } 29 30 public Dimension getPreferredSize() { return new Dimension(DEFAULT_WIDTH, DEFAULT_HEIGHT); } 31 32 public void paintComponent(Graphics g) 33 { 34 Graphics2D g2 = (Graphics2D) g; 35 36 // draw all squares 37 for (Rectangle2D r : squares) 38 g2.draw(r); 39 } 40 41 /** 42 * Finds the first square containing a point. 43 * @param p a point 44 * @return the first square that contains p 45 */ 46 public Rectangle2D find(Point2D p) 47 { 48 for (Rectangle2D r : squares) 49 { 50 if (r.contains(p)) return r; 51 } 52 return null; 53 } 54 55 /** 56 * Adds a square to the collection. 57 * @param p the center of the square 58 */ 59 public void add(Point2D p) 60 { 61 double x = p.getX(); 62 double y = p.getY(); 63 64 current = new Rectangle2D.Double(x - SIDELENGTH / 2, y - SIDELENGTH / 2, SIDELENGTH, 65 SIDELENGTH); 66 squares.add(current); 67 repaint(); 68 } 69 70 /** 71 * Removes a square from the collection. 72 * @param s the square to remove 73 */ 74 public void remove(Rectangle2D s) 75 { 76 if (s == null) return; 77 if (s == current) current = null; 78 squares.remove(s); 79 repaint(); 80 } 81 82 //兩個獨立的介面MouseListener和MouseMotionListener,有利於提高效率。 83 //當用戶移動滑鼠時,只關心滑鼠點選的監聽器就不會被多餘的滑鼠移動所困擾。 84 private class MouseHandler extends MouseAdapter 85 { 86 public void mousePressed(MouseEvent event) 87 { 88 // add a new square if the cursor isn't inside a square 89 //getPoint方法返回事件源元件左上角的x y座標 90 //判斷該處是否已經繪製圖形 91 current = find(event.getPoint()); 92 if (current == null) add(event.getPoint()); 93 } 94 95 public void mouseClicked(MouseEvent event) 96 { 97 // remove the current square if double clicked 98 current = find(event.getPoint()); 99 //雙擊滑鼠,擦除方塊 100 if (current != null && event.getClickCount() >= 2) remove(current); 101 } 102 } 103 104 private class MouseMotionHandler implements MouseMotionListener 105 { 106 //移動滑鼠的同時按下滑鼠,呼叫mouseMoved 107 public void mouseMoved(MouseEvent event) 108 { 109 // set the mouse cursor to cross hairs if it is inside 110 // a rectangle 111 //游標在一個小方塊之上時變成另外一種形狀(十字) 112 if (find(event.getPoint()) == null) setCursor(Cursor.getDefaultCursor()); 113 else setCursor(Cursor.getPredefinedCursor(Cursor.CROSSHAIR_CURSOR)); 114 } 115 116 //更新游標位置 117 public void mouseDragged(MouseEvent event) 118 { 119 if (current != null) 120 { 121 int x = event.getX(); 122 int y = event.getY(); 123 //設定形狀座標和大小 124 // drag the current rectangle to center it at (x, y) 125 current.setFrame(x - SIDELENGTH / 2, y - SIDELENGTH / 2, SIDELENGTH, SIDELENGTH); 126 repaint(); 127 } 128 } 129 } 130 }
如果只希望使用者能夠點選按鈕或選單,就不需要顯式地處理滑鼠事件。滑鼠操作將由使用者介面中的各種元件內部處理。然而,如果希望使用者使用滑鼠畫圖,就需要捕獲滑鼠移動點選和拖動事件。
當用戶點選滑鼠按鈕時,將會呼叫3個監聽器方法:滑鼠第一次被按下時呼叫mousePressed;滑鼠被釋放時呼叫mouseReleased;最後呼叫mouseClicked。如果只對最終的點選事件感興趣,就可以忽略前兩個方法。用MouseEvent類物件作為引數,呼叫getX和getY方法可以獲得滑鼠被按下時滑鼠指標所在的x和y座標。要想區分單擊、雙擊和三擊,需要使用getClickCount方法。
實驗2:結對程式設計練習
利用班級名單檔案、文字框和按鈕元件,設計一個有如下介面(圖1)的點名器,要求使用者點選開始按鈕後在文字輸入框隨機顯示2017級網路與資訊安全班同學姓名,如圖2所示,點選停止按鈕後,文字輸入框不再變換同學姓名,此同學則是被點到的同學姓名。
圖1 點名器啟動介面
圖2 點名器點名介面
1 package practise1; 2 3 import java.awt.*; 4 import javax.swing.*; 5 6 7 8 9 public class RandomName { 10 11 public static void main(String[] args) { 12 // TODO Auto-generated method stub 13 14 { 15 EventQueue.invokeLater(() -> { 16 JFrame A= new ButtonFrame(); 17 A.setTitle("點名器"); 18 A.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); 19 A.setVisible(true); 20 }); 21 } 22 } 23 24 }
1 package practise1; 2 3 import java.awt.Color; 4 import java.awt.Container; 5 import java.awt.event.*; 6 import java.io.*; 7 import java.util.*; 8 import java.util.Timer; 9 10 import javax.swing.*; 11 12 public class ButtonFrame extends JFrame { 13 private ArrayList arrayList; 14 15 16 17 { 18 arrayList = new ArrayList<>(); 19 //讀檔案 20 File file = new File("H:/List.txt"); 21 FileInputStream fis; 22 try { 23 fis = new FileInputStream(file); 24 InputStreamReader in = new InputStreamReader(fis); 25 BufferedReader buf = new BufferedReader(in); 26 String readLine; 27 while ((readLine = buf.readLine())!=null) { 28 arrayList.add(readLine); 29 30 } 31 } catch (FileNotFoundException e1) { 32 // TODO Auto-generated catch block 33 e1.printStackTrace(); 34 } catch (IOException e1) { 35 // TODO Auto-generated catch block 36 e1.printStackTrace(); 37 } 38 } 39 private JPanel buttonPanel; 40 private static final int DEFAULT_WIDTH = 500; 41 private static final int DEFAULT_HEIGHT = 300; 42 43 44 45 public ButtonFrame() { 46 setSize(DEFAULT_WIDTH, DEFAULT_HEIGHT); 47 buttonPanel = new JPanel(); 48 buttonPanel.setLayout(null); 49 JLabel jLabel = new JLabel("隨機點名器"); 50 JButton jButton = new JButton("開始"); 51 jLabel.setBounds(200, 40, 65, 40); 52 jButton.setBounds(200, 90, 65, 40); 53 54 55 56 jButton.addActionListener(new ActionListener() { 57 58 Timer timer; 59 60 61 62 public void actionPerformed(ActionEvent e) { 63 64 if (jButton.getText().equals("開始")) { 65 66 timer = new Timer();; 67 68 TimerTask timerTask = new TimerTask() { 69 70 public void run() { 71 72 jButton.setText("停止"); 73 74 jButton.setBackground(Color.red); 75 76 jLabel.setText((String) arrayList.get((int) (Math.random() * 43))); 77 78 } 79 80 81 82 }; 83 84 timer.schedule(timerTask, 0, 10); 85 86 } 87 88 if (jButton.getText().equals("停止")) { 89 90 timer.cancel(); 91 92 jButton.setText("開始"); 93 94 jButton.setBackground(Color.gray); 95 96 } 97 98 } 99 100 }); 101 102 103 104 105 buttonPanel.add(jLabel); 106 buttonPanel.add(jButton); 107 add(buttonPanel); 108 109 } 110 111 112 }
第三部分:總結
1.本週繼續深入學習學習GUI相關部分,事件處理。
2.測試程式一中三種方法的不斷優化了程式,使其簡練效率,以後的學習中要嘗試用不同的解決方法;
3.構造按鈕->將按鈕新增到面板上->構造監聽器->新增動作監聽器。