第十章
事件處理
10.1 事件類別
- 事件來源: 產生事件並管理聽候者(listener)
例: applet
- 聽候者(listener): 當事件發生時, 被告知
例: MouseListener
- 事件類別: 描述事件
例: MouseEvent
MouseListener 介面
public interface MouseListener
{
void mousePressed(MouseEvent event);
//Called when a mouse button has been pressed on a component
void mouseReleased(MouseEvent event);
//Called when a mouse button has been released on a component
void mouseClicked(MouseEvent event);
//Called when the mouse has been clicked on a component
void mouseEntered(MouseEvent event);
//Called when the mouse enters a component
void mouseExited(MouseEvent event);
//Called when the mouse exits a component
}
File MouseSpy.java
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;
/**
This listener simply prints out the listener method name
and the x- and y-coordinate of the mouse position.
*/
public class MouseSpy implements MouseListener
{
public void mousePressed(MouseEvent event)
{
System.out.println("Mouse pressed. x = "
+ event.getX() + " y = " + event.getY());
}
public void mouseReleased(MouseEvent event)
{
System.out.println("Mouse released. x = "
+ event.getX() + " y = " + event.getY());
}
public void mouseClicked(MouseEvent event)
{
System.out.println("Mouse clicked. x = "
+ event.getX() + " y = " + event.getY());
}
public void mouseEntered(MouseEvent event)
{
System.out.println("Mouse entered. x = "
+ event.getX() + " y = " + event.getY());
}
public void mouseExited(MouseEvent event)
{
System.out.println("Mouse exited. x = "
+ event.getX() + " y = " + event.getY());
}
}
File MouseSpyApplet.java
import java.applet.Applet;
/**
This applet installs a mouse spy. Try generating the
five mouse event types by moving and clicking the mouse.
*/
public class MouseSpyApplet extends Applet
{
public MouseSpyApplet()
{
MouseSpy listener = new MouseSpy();
addMouseListener(listener);
}
}
偵測滑鼠事件
10.2 處理滑鼠輸入
移動長方形的滑鼠聽候者
- 從事件物件取得滑鼠的位置
- 存取外一層類別的 box 個體變數
- 呼用在外一層類別的 repaint 方法
- repaint 觸發 paint 方法
- 總是應呼用 repaint 去觸發 paint 方法
不要直接呼用 paint
public MouseApplet()
{
...
//add mouse press listener
class MousePressListener implements MouseListener
{
public void mousePressed(MouseEvent event)
{
int x = event.getX();
int y = event.getY();
box.setLocation(x,y);
repaint();
}
//do-nothing methods
public void mouseReleased(MouseEvent event){}
public void mouseClicked(MouseEvent event){}
public void mouseEntered(MouseEvent event){}
public void mouseExited(MouseEvent event){}
}
MouseListener listener = new MousePressListener();
addMouseListener(listener);
}
The Mouse Applet
MouseApplet.java
import java.applet.Applet;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Rectangle;
import java.awt.event.MouseListener;
import java.awt.event.MouseEvent;
/**
This applet lets the user move a rectangle by clicking
the mouse.
*/
public class MouseApplet extends Applet
{
public MouseApplet()
{
// the rectangle that the paint method draws
box = new Rectangle(BOX_X, BOX_Y,
BOX_WIDTH, BOX_HEIGHT);
// add mouse press listener
class MousePressListener implements MouseListener
{
public void mousePressed(MouseEvent event)
{
int x = event.getX();
int y = event.getY();
box.setLocation(x, y);
repaint();
}
// do-nothing methods
public void mouseReleased(MouseEvent event) {}
public void mouseClicked(MouseEvent event) {}
public void mouseEntered(MouseEvent event) {}
public void mouseExited(MouseEvent event) {}
}
MouseListener listener = new MousePressListener();
addMouseListener(listener);
}
public void paint(Graphics g)
{
Graphics2D g2 = (Graphics2D)g;
g2.draw(box);
}
private Rectangle box;
private static final int BOX_X = 100;
private static final int BOX_Y = 100;
private static final int BOX_WIDTH = 20;
private static final int BOX_HEIGHT = 30;
}
10.3 處理文字輸入
有控制面板的小程式
控制面板(panel)元件
- 使用 Swing 套件 javax.swing
- 類別名稱以 J 起頭
- JTextField xField = new JTextField(width);
- JLabel xLabel = new JLabel("x = ");
- Icon buttonIcon = new ImageIcon("hand.gif");
- moveButton = new JButton("Move", buttonIcon);
按鈕聽候者
- 按下按鈕, 即移動長方形
- 從含蓋的適用範圍讀取 xField, yField 變數
public ButtonApplet()
{
...
class MoveButtonListener implements ActionListener
{
public void actionPerformed(ActionEvent event)
{
int x =Integer.parseInt(xField.getText());
int y =Integer.parseInt(yField.getText());
box.setLocation(x,y);
repaint();
}
};
ActionListener listener = new MoveButtonListener();
moveButton.addActionListener(listener);
...
}
在面板中放置元件
- JPanel 是元件的容器(container)
- 在面板中添加元件
JPanel panel = new JPanel();
panel.add(xLabel);
panel.add(xField);
. . .
- 將面板放入框架(frame)
JFrame frame = new JFrame();
frame.setContentPane(panel);
- 裝填框架: 調整框架大小,
剛好容得下這些元件
frame.pack();
frame.show();
File ButtonApplet.java
import java.applet.Applet;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Rectangle;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.ImageIcon;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.JTextField;
/**
This applet lets the user move a rectangle by specifying
the x- and y-position of the top left corner.
*/
public class ButtonApplet extends Applet
{
public ButtonApplet()
{
// the rectangle that the paint method draws
box = new Rectangle(BOX_X, BOX_Y,
BOX_WIDTH, BOX_HEIGHT);
// the text fields for entering the x- and y-coordinates
final JTextField xField = new JTextField(5);
final JTextField yField = new JTextField(5);
// the button to move the rectangle
JButton moveButton = new JButton("Move",
new ImageIcon("hand.gif"));
class MoveButtonListener implements ActionListener
{
public void actionPerformed(ActionEvent event)
{
int x = Integer.parseInt(xField.getText());
int y = Integer.parseInt(yField.getText());
box.setLocation(x, y);
repaint();
}
}
ActionListener listener = new MoveButtonListener();
moveButton.addActionListener(listener);
// the labels for labeling the text fields
JLabel xLabel = new JLabel("x = ");
JLabel yLabel = new JLabel("y = ");
// the panel for holding the user interface components
JPanel panel = new JPanel();
panel.add(xLabel);
panel.add(xField);
panel.add(yLabel);
panel.add(yField);
panel.add(moveButton);
// the frame for holding the component panel
JFrame frame = new JFrame();
frame.setContentPane(panel);
frame.pack();
frame.show();
}
public void paint(Graphics g)
{
Graphics2D g2 = (Graphics2D)g;
g2.draw(box);
}
private Rectangle box;
private static final int BOX_X = 100;
private static final int BOX_Y = 100;
private static final int BOX_WIDTH = 20;
private static final int BOX_HEIGHT = 30;
}
10.4 行為類似的按鈕組
有按鈕組的小程式
- 這四個按鈕要做的工作類似, 界定按鈕的程式碼重覆性很高:
JButton leftButton = new JButton("Left");
class LeftButtonListener implements ActionListener
{
public void actionPerformed(ActionEvent event)
{
box.setLocation(-BOX_WIDTH,0);
repaint();
}
};
LeftButtonListener leftListener = new ButtonListener();
leftButton.addActionListener(leftListener);
- 各個按鈕的程式碼只有在按鈕標記和移動量。
- 補救: 設計一方法, 可建構四個按鈕中任一個, 而將按鈕標記和移動量當做參數。
public JButton makeButton(String label, final int dx, final int dy)
{
JButton button = new JButton(label);
class ButtonListener implements ActionListener
{
public void actionPerformed(ActionEvent event)
{
box.translate(dx, dy);
repaint();
}
};
ButtonListener listener = new ButtonListener();
button.addActionListener(listener);
return button;
}
- 注意: 參數 dx 和 dy 宣告為 final。
- 如此, ButtonListener 才能夠存取這些參數。
- 呼用 makeButton 方法四次:
panel.add(makeButton("Left",-BOX_WIDTH,0));
panel.add(makeButton("Right",BOX_WIDTH,0));
panel.add(makeButton("Up",0,-BOX_HEIGHT));
panel.add(makeButton("Down",0,BOX_HEIGHT));
File ButtonApplet.java
import java.applet.Applet;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Rectangle;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JPanel;
/**
This applet lets the user move a rectangle by clicking
on buttons labeled "Left", "Right", "Up", and "Down".
*/
public class ButtonApplet extends Applet
{
public ButtonApplet()
{
// the rectangle that the paint method draws
box = new Rectangle(BOX_X, BOX_Y,
BOX_WIDTH, BOX_HEIGHT);
// the panel for holding the user interface components
JPanel panel = new JPanel();
panel.add(makeButton("Left", -BOX_WIDTH, 0));
panel.add(makeButton("Right", BOX_WIDTH, 0));
panel.add(makeButton("Up", 0, -BOX_HEIGHT));
panel.add(makeButton("Down", 0, BOX_HEIGHT));
// the frame for holding the component panel
JFrame frame = new JFrame();
frame.setContentPane(panel);
frame.pack();
frame.show();
}
public void paint(Graphics g)
{
Graphics2D g2 = (Graphics2D)g;
g2.draw(box);
}
/**
Makes a button that moves the box.
@param label the label to show on the button
@param dx the amount by which to move the box in x-direction
when the button is clicked
@param dy the amount by which to move the box in y-direction
when the button is clicked
@return the button
*/
public JButton makeButton(String label, final int dx,
final int dy)
{
JButton button = new JButton(label);
class ButtonListener implements ActionListener
{
public void actionPerformed(ActionEvent event)
{
box.translate(dx, dy);
repaint();
}
}
ButtonListener listener = new ButtonListener();
button.addActionListener(listener);
return button;
}
private Rectangle box;
private static final int BOX_X = 100;
private static final int BOX_Y = 100;
private static final int BOX_WIDTH = 20;
private static final int BOX_HEIGHT = 30;
}
10.5 框架視窗
- 應用程式, 不是小程式
- 建構並顯示框架
JFrame frame = new JFrame();
. . .
frame.show();
- 設定預設的關閉運算
frame.setDefaultCloseOperation(EXIT_ON_CLOSE);
- 將元件加入面板, 然後將面板設為內容格(pane)
JPanel panel = new
JPanel();
panel.add(. . .);
panel.add(. . .)
frame.setContentPane(panel);
A Frame with Two Labels
File FrameTest.java
import javax.swing.ImageIcon;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
/**
This program displays a frame with an image and a text label.
*/
public class FrameTest
{
public static void main(String[] args)
{
JFrame frame = new JFrame();
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
JLabel iconLabel = new JLabel(new ImageIcon("world.gif"));
JLabel textLabel = new JLabel("Hello, World!");
JPanel panel = new JPanel();
panel.add(iconLabel);
panel.add(textLabel);
frame.setContentPane(panel);
frame.pack();
frame.show();
}
}
10.6 文字元件
A Text Area with Scroll Bars
The Control Panel for Adding Interest
File TextAreaTest.java
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.JTextArea;
import javax.swing.JTextField;
/**
This program shows a frame with a text area that displays
the growth of an investment. A second frame holds a text
field to specify the interest rate.
*/
public class TextAreaTest
{
public static void main(String[] args)
{
// the application adds interest to this bank account
final BankAccount account = new BankAccount(INITIAL_BALANCE);
// the text area for displaying the results
final JTextArea textArea = new JTextArea(10, 30);
textArea.setEditable(false);
JScrollPane scrollPane = new JScrollPane(textArea);
// construct the frame for displaying the text area
JFrame frame = new JFrame();
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setContentPane(scrollPane);
frame.pack();
frame.show();
// the label and text field for entering the interest rate
JLabel rateLabel = new JLabel("Interest Rate: ");
final JTextField rateField = new JTextField(10);
rateField.setText("" + DEFAULT_RATE);
// the button to trigger the calculation
JButton calculateButton = new JButton("Add Interest");
class CalculateListener implements ActionListener
{
public void actionPerformed(ActionEvent event)
{
double rate = Double.parseDouble(
rateField.getText());
double interest = account.getBalance()
* rate / 100;
account.deposit(interest);
textArea.append(account.getBalance() + "\n");
}
}
ActionListener listener = new CalculateListener();
calculateButton.addActionListener(listener);
// the control panel that holds the input components
JPanel controlPanel = new JPanel();
controlPanel.add(rateLabel);
controlPanel.add(rateField);
controlPanel.add(calculateButton);
// the frame to hold the control panel
JFrame controlFrame = new JFrame();
controlFrame.setContentPane(controlPanel);
controlFrame.pack();
controlFrame.show();
}
private static final double DEFAULT_RATE = 10;
private static final double INITIAL_BALANCE = 1000;
}