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

来源:互联网 发布:kenzo知乎 编辑:程序博客网 时间:2024/05/23 01:19

        如果希望可以编写一个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。监听器通过更新画面来模拟动画。




0 0
原创粉丝点击