您的位置:首页 > 其它

事件驱动程序设计学习笔记

2015-12-11 10:00 344 查看
如果希望可以编写一个GUI程序提示用户输入贷款总额,年利率,年数,然后点击OK按钮获取月偿还额和总偿还额。则必须使用时间驱动程序设计来编写代码。

事件和事件源

能创建一个事件并能触发该事件的组件成为源对象或是源组件。如按钮是按钮点击动作事件的源对象。一个事件是一个事件类的实例化。事件的根类是java.util.EventObject。



除了ListSelectionEvent和ChangeEvent之外所有的事件类都包括在java.awt.event包中,ListSelectionEvent和ChangeEvent在java.swing.event包中。AWT事件本来就是为了AWT组件设计的,但是很多Swing组件都会用到它们。

监听器,注册,处理事件

Java使用一种基于委托的模型来处理事件:源对象触发一个事件,对此事件感兴趣的对象会处理它。对此事件感兴趣的对象成为监听器(listener)。一个对象要成为源对象的监听器需要具备两个条件:

1. 监听器对象的类必须是相应的事件监听器接口的实例,以确保监听器有处理这个时间的正确方法。

2. 监听器对象必须有源对象注册。



现在我们可以编写一个程序,使用两个按钮控制一个圆的大小。代码如下

import java.util.*;
import javax.swing.*;
import javax.swing.border.Border;
import java.io.*;
import java.awt.*;
import java.awt.event.*;

class ArcPanel extends JPanel {
private int radius = 5;

protected void paintComponent(Graphics g) {
super.paintComponent(g);
g.drawOval(getWidth() / 2 - radius, getHeight() / 2 - radius, 2 * radius, 2 * radius);
}

public void enlarge() {
radius += 5;
repaint();
}

public void shrink() {
radius -= 5;
repaint();
}
}

public class Main extends JFrame {

private JButton jbtEnlarge = new JButton("Enlarge");
private JButton jbtShrink = new JButton("Shrink");
private ArcPanel canvas = new ArcPanel();

public Main() {
JPanel panel = new JPanel();
panel.add(jbtEnlarge);
panel.add(jbtShrink);
this.add(canvas, BorderLayout.CENTER);
this.add(panel, BorderLayout.SOUTH);

jbtEnlarge.addActionListener(new EnlargeListener());
jbtShrink.addActionListener(new ShrinkListener());
}

class EnlargeListener implements ActionListener {
public void actionPerformed(ActionEvent e) {
canvas.enlarge();
}
}

class ShrinkListener implements ActionListener {
public void actionPerformed(ActionEvent e) {
canvas.shrink();
}
}

public static void main(String[] args) {
Main frame = new Main();
frame.setTitle("Main");
frame.setSize(250, 300);
frame.setLocationRelativeTo(null);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setVisible(true);
}
}

由上面的代码显示,我将EnlargeListener和ShrinListener定义成了内部类,通常,如果一个类只是被外部类使用,就将该类定义为内部类。一个内部类有如下特征:

1. 一个内部类被编译成一个名为OutClass$InnerClass.class的类。

2. 内部类可以引用定义在它嵌套外部类中的数据和方法,所以,不需要将外部类对象的引用传递给内部类的构造方法,因此,内部类可以使程序更加简单和简洁。

3. 使用可见修饰符定义内部类时,遵从应用与在类成员上一样的可见性原则。

4. 可以讲内部类定义为static。一个static内部类可以使用外部类的名字访问。一个static类是不能访问外部类的非静态成员的。

5. 内部类对象经常在外部类中创建。但是也可以从另一个类中创建一个内部类的对象,如果该内部类是非静态的,必须先创建一个外部类的实例,然后使用下面的语法创建以一个内部类对象:

OutClass.InnerClassinnerObject = outObject.new InnerClass();

6. 如果内部类是静态的,那么使用下面的语法为它创建一个对象:

OutClass.InnerClassinnObject = new OutClass.InnerClass();

匿名内部类:

我们可以把上面的监听器重新写,代码如下:

jbtEnlarge.addActionListener(new ActionListener()
{
public void actionPerformed(ActionListen e)
{
canvas.enlarge();
}
})

匿名内部类:

1. 匿名内部类必须总是扩展父类或实现接口,但是它不能有显示的extends或者implements子句。

2. 匿名类必须实现父类或者接口内的所有方法。

3. 匿名内部类总是使用它的父类的无参构造方法来创建实例,如果匿名内部类实现了接口,构造方法就是Object();

4. 匿名内部类被编译为一个名为OuterClassName$n.class的类。

定义监听器的另外一种方式

话不多说,贴上代码:

import java.util.*;
import javax.swing.*;
import javax.swing.border.Border;
import java.io.*;
import java.awt.*;
import java.awt.event.*;

public class Main extends JFrame {

private JButton jbtEnlarge = new JButton("Enlarge");
private JButton jbtShrink = new JButton("Shrink");
private ArcPanel canvas = new ArcPanel();
private ButtonListener listener = new ButtonListener();
public Main() {
JPanel panel = new JPanel();
panel.add(jbtEnlarge);
panel.add(jbtShrink);
this.add(canvas, BorderLayout.CENTER);
this.add(panel, BorderLayout.SOUTH);

jbtEnlarge.addActionListener(listener);
jbtShrink.addActionListener(listener);
}

class ButtonListener implements ActionListener
{
public void actionPerformed(ActionEvent e)
{
if(e.getSource() == jbtEnlarge)
canvas.enlarge();
else if(e.getSource() == jbtShrink)
canvas.shrink();
}
}

class ArcPanel extends JPanel {
private int radius = 5;

protected void paintComponent(Graphics g) {
super.paintComponent(g);
g.drawOval(getWidth() / 2 - radius, getHeight() / 2 - radius, 2 * radius, 2 * radius);
}

public void enlarge() {
radius += 5;
repaint();
}

public void shrink() {
radius -= 5;
repaint();
}
}

public static void main(String[] args) {
Main frame = new Main();
frame.setTitle("Main");
frame.setSize(250, 300);
frame.setLocationRelativeTo(null);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setVisible(true);
}
}

如上代码所示,我们只定义了一个监听器 listener。我们可以通过getSource()方法获取我们鼠标点击的按钮,这样可以减少类的定义从而简化代码。

实例:贷款计算器

要求:

(1) 创建一个如图所示的用户接口

(2) 创建一个5行2列的GridLayout面板,添加文本和标签

(3) 创建一个FlowLayout面板,并添加一个按钮

(4) 将两个面板添加到框架中

(5) 处理事件



代码如下:

import java.util.*;
import javax.swing.*;
import javax.swing.border.Border;
import javax.swing.border.TitledBorder;

import java.io.*;
import java.awt.*;
import java.awt.event.*;

public class Main extends JFrame {
private JTextField jtfAnnualInterestRate = new JTextField("please type rate here");
private JTextField jtfNumberOfYears = new JTextField("please type year here");
private JTextField jtfLoanAmount = new JTextField("please type loanAmount here");
private JTextField jtfMonthlyPayment = new JTextField("output");
private JTextField jtfTotalPayment = new JTextField("output");

private JButton jbtComputeLoan = new JButton("Compute Payment");
public class ButtonListener implements ActionListener
{

public void actionPerformed(ActionEvent e) {
double interest = Double.parseDouble(jtfAnnualInterestRate.getText());
int year = Integer.parseInt(jtfNumberOfYears.getText());
double loanAmount = Double.parseDouble(jtfLoanAmount.getText());
//     loan(interest,year,loanAmount);
jtfMonthlyPayment.setText(String.format("%.2f", loanAmount));//这里只是一个替代。。。。。
jtfTotalPayment.setText(String.format("%.2f", loanAmount));// 这里只是一个替代。。。。。

}

}
public Main()
{
JPanel p1 = new JPanel(new GridLayout(5,2));
p1.add(new JLabel("Annual Interest Rate"));
p1.add(jtfAnnualInterestRate);
p1.add(new JLabel("Number of Years"));
p1.add(jtfNumberOfYears);
p1.add(new JLabel("Loan Amount"));
p1.add(jtfLoanAmount);
p1.add(new JLabel("Monthly Payment"));
p1.add(jtfMonthlyPayment);
p1.add(new JLabel("Total Payment"));
p1.add(jtfTotalPayment);
p1.setBorder(new TitledBorder("Enter loan amount,interest rate,and year"));
JPanel p2 = new JPanel(new FlowLayout(FlowLayout.RIGHT));
p2.add(jbtComputeLoan);
add(p1,BorderLayout.CENTER);
add(p2,BorderLayout.SOUTH);
jbtComputeLoan.addActionListener(new ButtonListener());

}
public static void main(String[] args) {
Main frame = new Main();
frame.pack();
frame.setTitle("LoanCalculator");
frame.setLocationRelativeTo(null);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setVisible(true);
}
}

Loan类的实现我已经实现过了,可是文件丢失了,然后我又不想再写一遍。。。。。

实例学习:使用鼠标在面板上拖动消息(用到方便适配器)

上代码:

import java.util.*;
import java.util.Timer;

import javax.swing.*;
import javax.swing.border.Border;
import javax.swing.border.TitledBorder;

import java.io.*;
import java.awt.*;
import java.awt.event.*;

public class Main extends JFrame {
static class MovableMessagePanel extends JPanel {
private String s = "Welcomea To Java!";
private int x = 20;
private int y = 20;

public MovableMessagePanel(String s) {
this.s = s;
addMouseMotionListener(new MouseAdapter() {
public void mouseDragged(MouseEvent e) {
x = e.getX();
y = e.getY();
repaint();
}
});
}
protected void paintComponent(Graphics g)
{
super.paintComponent(g);
g.drawString(s, x, y);
}
}

public Main() {
MovableMessagePanel p =new MovableMessagePanel("Hello Java!");
setLayout(new BorderLayout());
add(p);
}

public static void main(String[] args) {
Main frame = new Main();
frame.setTitle("MoveMessageDemo");
frame.setSize(200,100);
frame.setLocationRelativeTo(null);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setVisible(true);
}
}


使用MouseMotionAdapter覆盖mouseDragged方法,如果内部类实现了MouseMotionListener接口,即使监听器并不关心某些事件,也必须要实现所有的处理器。

本章小结:

1. 事件类的根类是java.util.EventObject。EventObject的子类处理各种特殊类型的时间,例如动作事件,窗口时间,组件事件,鼠标事件和按键事件。可以使用EventObject类中的getSource()实例方法判断事件的源对象。如果一个组件能够触发整个事件,那么它的所有子类都能触发同类型的事件。

2. 监听器对象的类必须时间相应的时间监听器接口。Java语言为每种事件类提供监听器接口。XEvent的监听器接口通常命名为XListener,但是MouseMotionListener除外。例如,ActionEvent对应的监听器接口是ActionListener,每个ActionEvent的监听器都应该实现ActionListener接口,监听器接口包含成为处理器的处理事件的方法。

3. 监听器对象必须由源对象注册。注册方法依赖于事件的类型。对ActionEvent来讲,注册方法是addActionListener。一般来说XEvent的方法命名为addXListener。

4. 内部类或者是嵌套类是定义在另一个类中的类。内部类可以应用定义在它嵌套的外部类中的数据和方法。所以,不需要将外部类的引用传递给内部类的构造方法。

5. 方便适配器能够提供监听器接口中所有方法的默认实现类的支持类。Java为每一个AWT监听器接口提供多个处理器的方便监听器适配器,XListenerde 方便监听器适配器命名为Xadapter。。

6. 一个源对象可以触发几种类型的事件。对每种事件,源对象维护一个注册的监听器列表,通过调用监听器对象的处理器,通知所有已经注册的监听器取处理事件。

7. 在一个组件上点击,释放,移动或拖动鼠标就会触发鼠标事件。鼠标事件对象捕获事件,例如和事件相关的点击次数和鼠标点的位置(x,y坐标)

8. Java提供两个处理鼠标事件的监听器接口,MouseListener和MouseMotionListner来处理事件,实现MouseListener接口来监听注入按下,释放,点击,输入或退出鼠标等动作,实现MouseMotionListener接口来监听注入移动或拖动鼠标的动作。

9. KeyEvent对象描述事件的性质(即按下,释放或敲击一个键)以及相对应的键值

10. 当按下按键是就会调用keyPressed处理器,当释放按键时会调用keyReleased处理器,而当敲入一个统一码字符键是,就会调用keyTyped处理器。如果某个按键没有统一码(如功能键,修改键,动作键和控制键),则不会调用keyTyped处理器。

可以使用Timer类控制Java的动画。定时器以固定频率触发ActionEvent。监听器通过更新画面来模拟动画。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: