1. 程式人生 > >王穎奇 20171010129《面向物件程式設計(java)》第十三週學習總結

王穎奇 20171010129《面向物件程式設計(java)》第十三週學習總結

  實驗十三  圖形介面事件處理技術

實驗時間 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 button;

import java.awt.*;
import javax.swing.*;

/**
 * @version 1.34 2015-06-12
 * @author Cay Horstmann
 */
public class ButtonTest
{
   public static void main(String[] args)
   {
       
//lambda表示式 EventQueue.invokeLater(() -> { JFrame frame = new ButtonFrame(); frame.setTitle("ButtonTest"); frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); frame.setVisible(true); }); } }
ButtonTest
package button;

import java.awt.*;
import java.awt.event.*; import javax.swing.*; /** * A frame with a button panel */ public class ButtonFrame extends JFrame { private JPanel buttonPanel; private static final int DEFAULT_WIDTH = 300; private static final int DEFAULT_HEIGHT = 200; public ButtonFrame() { setSize(DEFAULT_WIDTH, DEFAULT_HEIGHT); // 建立一個帶文字的按鈕 JButton yellowButton = new JButton("Yellow"); JButton blueButton = new JButton("Blue"); JButton redButton = new JButton("Red"); buttonPanel = new JPanel(); // 新增按鈕到JPanel中 buttonPanel.add(yellowButton); buttonPanel.add(blueButton); buttonPanel.add(redButton); // 新增JPanel到框架中 add(buttonPanel); // 建立按鈕操作 ColorAction yellowAction = new ColorAction(Color.YELLOW); ColorAction blueAction = new ColorAction(Color.BLUE); ColorAction redAction = new ColorAction(Color.RED); // 把操作關聯至按鈕上 yellowButton.addActionListener(yellowAction); blueButton.addActionListener(blueAction); redButton.addActionListener(redAction); } /** * An action listener that sets the panel's background color. */ private class ColorAction implements ActionListener //新增事件監聽器 { //設定私有屬性backgroundColor private Color backgroundColor; public ColorAction(Color c) { backgroundColor = c; } public void actionPerformed(ActionEvent event) //在事件發生時,呼叫actionPerformed方法 { buttonPanel.setBackground(backgroundColor); } } }
ButtonFrame

執行結果:

略微簡化後的ButtonFrame:

package button;

import java.awt.*;
import java.awt.event.*;
import javax.swing.*;

/**
 * A frame with a button panel
 */
public class ButtonFrame extends JFrame
{
   private JPanel buttonPanel;
   private static final int DEFAULT_WIDTH = 300;
   private static final int DEFAULT_HEIGHT = 200;

   public ButtonFrame()
   {      
      setSize(DEFAULT_WIDTH, DEFAULT_HEIGHT);
      buttonPanel = new JPanel();

      // add buttons to panel
      /*buttonPanel.add(yellowButton);
      buttonPanel.add(blueButton);
      buttonPanel.add(redButton);*/

      // add panel to frame
      add(buttonPanel);

      // create button actions
      /*ColorAction yellowAction = new ColorAction(Color.YELLOW);
      ColorAction blueAction = new ColorAction(Color.BLUE);
      ColorAction redAction = new ColorAction(Color.RED);*/

      // associate actions with buttons
      /*yellowButton.addActionListener(yellowAction);
      blueButton.addActionListener(blueAction);
      redButton.addActionListener(redAction);*/
      makeButton("Yellow",Color.YELLOW);
      makeButton("Blue",Color.BLUE);
      makeButton("Red",Color.RED);
   }
   public void makeButton(String name , Color backgroundColor)
   {
   JButton button=new JButton(name);
   buttonPanel.add(button);
   ColorAction action=new ColorAction(backgroundColor);
   button.addActionListener(action);
   }
   /**
    * An action listener that sets the panel's background color.
    */
   private class ColorAction implements ActionListener
   {
      private Color backgroundColor;

      public ColorAction(Color c)
      {
         backgroundColor = c;
      }

      public void actionPerformed(ActionEvent event)
      {
         buttonPanel.setBackground(backgroundColor);
      }
   }
}
ButtonFrame

lambda表示式簡化後的ButtonFrame:

package demo;

import java.awt.*;
import java.awt.event.*;
import javax.swing.*;

/**
 * A frame with a button panel
 */
public class ButtonFrame extends JFrame {
    private JPanel buttonPanel;
    private static final int DEFAULT_WIDTH = 300*2;
    private static final int DEFAULT_HEIGHT = 200*2;

    public ButtonFrame() {
        setSize(DEFAULT_WIDTH, DEFAULT_HEIGHT);
        buttonPanel = new JPanel();
        makeButton("黃色", Color.yellow);
        makeButton("藍色", Color.blue);
        makeButton("紅色", Color.red);
        makeButton("綠色",Color.green);
        add(buttonPanel);

    }

    protected void makeButton(String name,Color backgound) {
        // create buttons
        JButton button = new JButton(name);
        // add buttons to panel
        buttonPanel.add(button);
        // create button actions
        //方法一:通過內部類方式實現
        /*ColorAction action = new ColorAction(backgound);
        // associate actions with buttons
        button.addActionListener(action);*/
        //方法二:匿名內部類方式實現
        /*button.addActionListener(new ActionListener() {
            public void actionPerformed(ActionEvent e) {
                buttonPanel.setBackground(background);
            }
        });*/
        //方法三通過lambda表示式實現
        button.addActionListener((e)->{
            buttonPanel.setBackground(backgound);
        });
        
    }

    /**
     * An action listener that sets the panel's background color.
     */
    //這是實現了 ActionListener介面的內部類
    /*private class ColorAction implements ActionListener {
        private Color backgroundColor;

        public ColorAction(Color c) {
            backgroundColor = c;
        }

        public void actionPerformed(ActionEvent event) {
            buttonPanel.setBackground(backgroundColor);
        }
    }*/
}
ButtonFrame

 測試程式2

elipse IDE中除錯執行教材449頁程式11-2,結合程式執行結果理解程式;

在元件觀感設定程式碼處添加註釋;

瞭解GUI程式中觀感的設定方法。

程式碼:

package plaf;

import java.awt.*;
import javax.swing.*;

/**
 * @version 1.32 2015-06-12
 * @author Cay Horstmann
 */
public class PlafTest
{
   public static void main(String[] args)
   {
      EventQueue.invokeLater(() -> {
         JFrame frame = new PlafFrame();
         frame.setTitle("PlafTest");
         frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
         frame.setVisible(true);
      });
   }
}
PlafTes

 

package plaf;

import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.SwingUtilities;
import javax.swing.UIManager;

/**
 * A frame with a button panel for changing look-and-feel
 */
public class PlafFrame extends JFrame
{
   private JPanel buttonPanel;

   public PlafFrame()
   {
      buttonPanel = new JPanel();
      //UIManager管理元件觀感
      UIManager.LookAndFeelInfo[] infos = UIManager.getInstalledLookAndFeels();
      for (UIManager.LookAndFeelInfo info : infos)
         makeButton(info.getName(), info.getClassName());

      add(buttonPanel);
      pack();
   }

   /**
    * Makes a button to change the pluggable look-and-feel.
    * @param name the button name
    * @param className the name of the look-and-feel class
    */
   private void makeButton(String name, String className)
   {
      // 新增按鈕至Panel

      JButton button = new JButton(name);
      buttonPanel.add(button);

      // 建立按鈕操作

      button.addActionListener(event -> {
         // 按鈕操作: 選擇一個新的外觀
         try
         {
            UIManager.setLookAndFeel(className);
            SwingUtilities.updateComponentTreeUI(this);
            pack();
         }
         catch (Exception e)
         {
            e.printStackTrace();
         }
      });
   }
}
PlafFrame

 測試程式3

elipse IDE中除錯執行教材457-458頁程式11-3,結合程式執行結果理解程式;

掌握AbstractAction類及其動作物件;

掌握GUI程式中按鈕、鍵盤動作對映到動作物件的方法。

程式碼:

package action;

import java.awt.*;
import javax.swing.*;

/**
 * @version 1.34 2015-06-12
 * @author Cay Horstmann
 */
public class ActionTest
{
   public static void main(String[] args)
   {
      EventQueue.invokeLater(() -> {
         JFrame frame = new ActionFrame();
         frame.setTitle("ActionTest");
         frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
         frame.setVisible(true);
      });
   }
}
ActionTest

 

package action;

import java.awt.*;
import java.awt.event.*;
import javax.swing.*;

/**
 * A frame with a panel that demonstrates color change actions.
 */
public class ActionFrame extends JFrame
{
   private JPanel buttonPanel;
   private static final int DEFAULT_WIDTH = 300;
   private static final int DEFAULT_HEIGHT = 200;

   public ActionFrame()
   {
      setSize(DEFAULT_WIDTH, DEFAULT_HEIGHT);

      buttonPanel = new JPanel();

      // define actions
      Action yellowAction = new ColorAction("Yellow", new ImageIcon("yellow-ball.gif"),
            Color.YELLOW);
      Action blueAction = new ColorAction("Blue", new ImageIcon("blue-ball.gif"), Color.BLUE);
      Action redAction = new ColorAction("Red", new ImageIcon("red-ball.gif"), Color.RED);

      // add buttons for these actions
      buttonPanel.add(new JButton(yellowAction));
      buttonPanel.add(new JButton(blueAction));
      buttonPanel.add(new JButton(redAction));

      // add panel to frame
      add(buttonPanel);

      // associate the Y, B, and R keys with names
      InputMap imap = buttonPanel.getInputMap(JComponent.WHEN_ANCESTOR_OF_FOCUSED_COMPONENT);
      imap.put(KeyStroke.getKeyStroke("ctrl Y"), "panel.yellow");
      imap.put(KeyStroke.getKeyStroke("ctrl B"), "panel.blue");
      imap.put(KeyStroke.getKeyStroke("ctrl R"), "panel.red");

      // associate the names with actions
      ActionMap amap = buttonPanel.getActionMap();
      amap.put("panel.yellow", yellowAction);
      amap.put("panel.blue", blueAction);
      amap.put("panel.red", redAction);
   }
   
   public class ColorAction extends AbstractAction
   {
      /**
       * Constructs a color action.
       * @param name the name to show on the button
       * @param icon the icon to display on the button
       * @param c the background color
       */
      public ColorAction(String name, Icon icon, Color c)
      {
         putValue(Action.NAME, name);
         putValue(Action.SMALL_ICON, icon);
         putValue(Action.SHORT_DESCRIPTION, "Set panel color to " + name.toLowerCase());
         putValue("color", c);
      }

      public void actionPerformed(ActionEvent event)
      {
         Color c = (Color) getValue("color");
         buttonPanel.setBackground(c);
      }
   }
}
ActionFrame

執行結果:

測試程式4

elipse IDE中除錯執行教材462頁程式11-411-5,結合程式執行結果理解程式;

掌握GUI程式中滑鼠事件處理技術。

程式碼:

package mouse;

import java.awt.*;
import javax.swing.*;

/**
 * @version 1.34 2015-06-12
 * @author Cay Horstmann
 */
public class MouseTest
{
   public static void main(String[] args)
   {
      EventQueue.invokeLater(() -> {
         JFrame frame = new MouseFrame();
         frame.setTitle("MouseTest");
         frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
         frame.setVisible(true);
      });
   }
}
MouseTest

 

package mouse;

import javax.swing.*;

/**
 * A frame containing a panel for testing mouse operations
 */
public class MouseFrame extends JFrame
{
   public MouseFrame()
   {
      add(new MouseComponent());
      pack();
   }
}
MouseFrame
package mouse;

import java.awt.*;
import java.awt.event.*;
import java.awt.geom.*;
import java.util.*;
import javax.swing.*;

/**
 * A component with mouse operations for adding and removing squares.
 */
public class MouseComponent extends JComponent
{
   private static final int DEFAULT_WIDTH = 300;
   private static final int DEFAULT_HEIGHT = 200;

   private static final int SIDELENGTH = 10;
   private ArrayList<Rectangle2D> squares;
   private Rectangle2D current; // the square containing the mouse cursor

   public MouseComponent()
   {
      squares = new ArrayList<>();
      current = null;

      addMouseListener(new MouseHandler());
      addMouseMotionListener(new MouseMotionHandler());
   }

   public Dimension getPreferredSize() { return new Dimension(DEFAULT_WIDTH, DEFAULT_HEIGHT); }   
   
   public void paintComponent(Graphics g)
   {
      Graphics2D g2 = (Graphics2D) g;

      // draw all squares
      for (Rectangle2D r : squares)
         g2.draw(r);
   }

   /**
    * Finds the first square containing a point.
    * @param p a point
    * @return the first square that contains p
    */
   public Rectangle2D find(Point2D p)
   {
      for (Rectangle2D r : squares)
      {
         if (r.contains(p)) return r;
      }
      return null;
   }

   /**
    * Adds a square to the collection.
    * @param p the center of the square
    */
   public void add(Point2D p)
   {
      double x = p.getX();
      double y = p.getY();

      current = new Rectangle2D.Double(x - SIDELENGTH / 2, y - SIDELENGTH / 2, SIDELENGTH,
            SIDELENGTH);
      squares.add(current);
      repaint();
   }

   /**
    * Removes a square from the collection.
    * @param s the square to remove
    */
   public void remove(Rectangle2D s)
   {
      if (s == null) return;
      if (s == current) current = null;
      squares.remove(s);
      repaint();
   }

   private class MouseHandler extends MouseAdapter
   {
      public void mousePressed(MouseEvent event)
      {
         // add a new square if the cursor isn't inside a square
         current = find(event.getPoint());
         if (current == null) add(event.getPoint());
      }

      public void mouseClicked(MouseEvent event)
      {
         // remove the current square if double clicked
         current = find(event.getPoint());
         if (current != null && event.getClickCount() >= 2) remove(current);
      }
   }

   private class MouseMotionHandler implements MouseMotionListener
   {
      public void mouseMoved(MouseEvent event)
      {
         // set the mouse cursor to cross hairs if it is inside
         // a rectangle

         if (find(event.getPoint()) == null) setCursor(Cursor.getDefaultCursor());
         else setCursor(Cursor.getPredefinedCursor(Cursor.CROSSHAIR_CURSOR));
      }

      public void mouseDragged(MouseEvent event)
      {
         if (current != null)
         {
            int x = event.getX();
            int y = event.getY();

            // drag the current rectangle to center it at (x, y)
            current.setFrame(x - SIDELENGTH / 2, y - SIDELENGTH / 2, SIDELENGTH, SIDELENGTH);
            repaint();
         }
      }
   }   
}
MouseComponent

執行結果:

實驗2:結對程式設計練習

利用班級名單檔案、文字框和按鈕元件,設計一個有如下介面(圖1)的點名器,要求使用者點選開始按鈕後在文字輸入框隨機顯示2017級網路與資訊安全班同學姓名,如圖2所示,點選停止按鈕後,文字輸入框不再變換同學姓名,此同學則是被點到的同學姓名。

程式碼(本人編寫,無法實現停止點名):

package demo;

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("隨機點名器");
            frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
            frame.setVisible(true);
        });
    }
}
ButtonTest

 

package demo;

import java.awt.Color;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Scanner;
import java.util.Timer;
import java.util.TimerTask;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;

/**
 * A frame with a button panel
 * 
 * @param <SheThread>
 */
public class ButtonFrame extends JFrame {
    private static ArrayList<String> studentlist;
    private JPanel buttonPanel;
    private static final int DEFAULT_WIDTH = 300;
    private static final int DEFAULT_HEIGHT = 200;
    private static volatile boolean flag = false;

    public ButtonFrame() {
        try {
            String temp = null;
            studentlist = new ArrayList<String>();
            File file = new File("C:\\Users\\ASUS\\Desktop\\studentnamelist.txt");
            FileInputStream fis = new FileInputStream(file);
            BufferedReader in = new BufferedReader(new InputStreamReader(fis));
            while ((temp = in.readLine()) != null) {
                Scanner linescanner = new Scanner(temp);
                linescanner.useDelimiter(" ");
                studentlist.add(temp);
            }
            String[] arr = (String[]) studentlist.toArray(new String[studentlist.size()]);
            setSize(DEFAULT_WIDTH, DEFAULT_HEIGHT);

            buttonPanel = new JPanel();
            buttonPanel.setLayout(null);
            JLabel jLabel = new JLabel("隨機點名器");
            JButton jButton = new JButton("點名");
            JButton jbutton = new JButton("點名");
            jLabel.setBounds(130, 40, 200, 30);
            jButton.setBounds(110, 90, 60, 30);
            buttonPanel.setBackground(Color.GREEN);
            jButton.setBackground(Color.RED);

            jButton.addActionListener(new ActionListener() {
                public void actionPerformed(ActionEvent e) {
                    Timer timer = new Timer();
                    TimerTask timerTask = new TimerTask() {
                        public void run() {
                            String[] name = arr;
                            jLabel.setText(name[(int) Math.round(Math.random() * 42)]);
                        }
                    };
                    timer.schedule(timerTask, 0, 500);
                }
            });

            buttonPanel.add(jLabel);
            buttonPanel.add(jButton);
            add(buttonPanel);

        } catch (FileNotFoundException e) {
            System.out.println("學生資訊檔案找不到");
            e.printStackTrace();
        } catch (IOException e) {
            System.out.println("學生資訊檔案讀取錯誤");
            e.printStackTrace();
        }

    }
}
ButtonFrame

執行結果:

示例程式碼(學長提供)

package demo;

import java.util.*;
import java.awt.*;
import javax.swing.*;
import java.awt.event.*;
import java.io.File;
import java.io.FileNotFoundException;

import javax.swing.event.*;
public class NameFrame extends JFrame implements ActionListener{
    private JLabel jla;
    private JLabel jlb;
    private JButton jba;
    private static boolean flag = true;
    public NameFrame(){
        this.setLayout(null);
      
        jla = new JLabel("姓名");
        jlb = new JLabel("準備中");
        jba = new JButton("開始");
        this.add(jla);
        this.add(jlb);
        jla.setFont(new Font("Courier",Font.PLAIN,22));
        jla.setHorizontalAlignment(JLabel.CENTER);
         jla.setVerticalAlignment(JLabel.CENTER);        
         jla.setBounds(20,100,180,30);
         jlb.setOpaque(true);
         jlb.setBackground(Color.cyan);
         jlb.setFont(new Font("Courier",Font.PLAIN,22));
        jlb.setHorizontalAlignment(JLabel.CENTER);
         jlb.setVerticalAlignment(JLabel.CENTER);        
         jlb.setBounds(150,100,120,30);
          
         this.add(jba);
         jba.setBounds(150,150,80,26);
      
         jba.addActionListener(this);

         this.setTitle("點名器");
        this.setBounds(400,400,400,300);
        this.setVisible(true);
        this.setDefaultCloseOperation(DISPOSE_ON_CLOSE);
    }
    public void actionPerformed(ActionEvent e){
        int i=0;
        String names[]=new String[50];
        try {
            Scanner in=new Scanner(new File("C:\\Users\\ASUS\\Desktop\\studentnamelist.txt"));
            while(in.hasNextLine())
            {
                names[i]=in.nextLine();
                i++;
            }
        } catch (FileNotFoundException e1) {
            // TODO Auto-generated catch block
            e1.printStackTrace();
        }
        if(jba.getText()=="開始"){
            jlb.setBackground(Color.MAGENTA);
            flag = true;
            new Thread(){   
                public void run(){
                    while(NameFrame.flag){
                    Random r = new Random(); 
                    int i= r.nextInt(47);
                    jlb.setText(names[i]);
                    }
                }
            }.start();
            jba.setText("停止");
            jba.setBackground(Color.YELLOW);
        }    
        else if(jba.getText()=="停止"){
            flag = false;
            jba.setText("開始");
            jba.setBackground(Color.WHITE);
            jlb.setBackground(Color.gray);
        }
     }
    public static void main(String arguments []){ 
        new NameFrame();
    }
}
NameFrame

由於本人未學習有關JAVA多執行緒的知識,無法實現執行緒的停止。

在查閱資料的過程中,本連結中的隨機點名方法不太瞭解:

https://blog.csdn.net/qq_39694972/article/details/83243673

此部分:

 

執行結果:

學習總結:

11.1 事件處理基礎
11.2 動作
11.3 滑鼠事件
11.4 AWT事件繼承層次

 

⚫ 事件源(event source):能夠產生事件的物件都可

以成為事件源,如文字框、按鈕等。一個事件源是一個能夠註冊監聽器並向監聽器傳送事件物件的物件。

⚫ 事件監聽器(event listener):事件監聽器物件接收事件源傳送的通告(事件物件),並對發生的事件作出響應。一個監聽器物件就是一個實現了專門監聽器介面的類例項,該類必須實現介面中的方法,這些方法當事件發生時,被自動執行。

⚫ 事件物件(event object):Java將事件的相關資訊封裝在一個事件物件中,所有的事件物件都最終派生於java.util.EventObject類。不同的事件源可以產生不同類別的事件。

AWT事件處理機制的概要:

⚫ 監聽器物件:是一個實現了特定監聽器介面(listener interface)的類例項。

⚫ 事件源:是一個能夠註冊監聽器物件併發送事件物件的物件。

⚫ 當事件發生時,事件源將事件物件自動傳遞給所有註冊的監聽器。

⚫ 監聽器物件利用事件物件中的資訊決定如何對事件做出響應。

GUI設計中,程式設計師需要對元件的某種事件進行響應和處理時,必須完成兩個步驟:

1) 定義實現某事件監聽器介面的事件監聽器類,並具體化介面中宣告的事件處理抽象方法。

2) 為元件註冊實現了規定介面的事件監聽器物件;

動作事件(ActionEvent):當特定元件動作(點選按鈕)發生時,該元件生成此動作事件。

⚫ 該 事 件 被 傳 遞 給 組 件 注 冊 的 每 一 個ActionListener 對 象 , 並 調 用 監 聽 器 對 象 的actionPerformed方法以接收這類事件物件。

⚫ 能夠觸發動作事件的動作,主要包括:

(1) 點選按鈕

(2) 雙擊一個列表中的選項;

(3) 選擇選單項;

監聽器類必須實現與事件源相對應的介面,即必須提供介面中方法的實現。

 學習感受:

這個周的結對程式設計練習,由於未學習JAVA多執行緒的知識,無法完全實現程式設計題的內容(隨機點名器不能停止),深感自己知識的不夠。在我查閱資料的過程中,有些看不懂中斷執行緒的兩種方法:stop()和interrupt()方法。