26、Java 事件处理与小程序开发全解析

Java 事件处理与小程序开发全解析

1. Java 事件处理基础

1.1 确认按钮点击对象

在 Java 编程中,我们常常需要确认被点击的对象。可以通过编写 if (e.getSource() == button) 这样的代码来进行测试,以此确保 button 变量所引用的对象确实是被点击的那个。若代码中有两个按钮 button1 button2 ,则可以使用 if (e.getSource() == button1) if (e.getSource() == button2) 来判断哪个按钮被点击了。

1.2 serialVersionUID 的作用

serialVersionUID 是一个有助于 Java 在对象传输时避免版本冲突的数字。例如,当我们将 JFrame 对象的状态发送到另一台计算机的屏幕时,接收方计算机可以通过检查该框架的版本号,确保不会出现异常情况。通常,我们可以通过 @SuppressWarnings 注解来避免处理 serialVersionUID 相关的警告。但在某些情况下,我们也可以为 JFrame 对象赋予一个真实的 serialVersionUID 。比如,对于 GameFrame 的第一个版本,我们可以将其版本号设为 1L 。不过,除非对类的代码进行了不兼容的更改,否则不要随意更改 serialVersionUID 的值。这里的“不兼容更改”指的是那些会使接收方计算机的现有代码无法处理新创建对象的更改。更多关于 serialVersionUID 以及不兼容代码更改的详细信息,可查看 相关文档

1.3 响应非按钮点击事件

当我们掌握了对一种事件的响应方法后,处理其他类型的事件就会变得容易。以下是一个用于实现美元与英镑货币转换的示例代码,它能够响应多种事件:

import java.awt.Color;
import java.awt.FlowLayout;
import java.awt.event.ItemEvent;
import java.awt.event.ItemListener;
import java.awt.event.KeyEvent;
import java.awt.event.KeyListener;
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;
import java.text.NumberFormat;
import java.util.Locale;
import javax.swing.JComboBox;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JTextField;

class MoneyFrame extends JFrame implements 
              KeyListener, ItemListener, MouseListener {
    private static final long serialVersionUID = 1L;

    JLabel fromCurrencyLabel = new JLabel(" ");
    JTextField textField = new JTextField(5);
    JLabel label = new JLabel("           ");
    JComboBox combo = new JComboBox();
    NumberFormat currencyUS = 
        NumberFormat.getCurrencyInstance();
    NumberFormat currencyUK = 
        NumberFormat.getCurrencyInstance(Locale.UK);

    public MoneyFrame() {
        setLayout(new FlowLayout());
        add(fromCurrencyLabel);
        add(textField);
        combo.addItem("US to UK");
        combo.addItem("UK to US");
        add(label);
        add(combo);
        textField.addKeyListener(this);
        combo.addItemListener(this);
        label.addMouseListener(this);
        setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        setSize(300, 100);
        setVisible(true);
    }

    void setTextOnLabel() {
        String amountString = "";
        String fromCurrency = "";

        try {
            double amount = 
                Double.parseDouble(textField.getText());
            if(combo.getSelectedItem().equals("US to UK")) 
            {
                amountString = " = " + 
                      currencyUK.format(amount * 0.61214);
                fromCurrency = "$";
            }
            if(combo.getSelectedItem().equals("UK to US")) 
            {
                amountString = " = " + 
                      currencyUS.format(amount * 1.63361);
                fromCurrency = "\u00A3";            
            }

        } catch (NumberFormatException e) {
        }
        label.setText(amountString);
        fromCurrencyLabel.setText(fromCurrency);
    }

    @Override
    public void keyReleased(KeyEvent k) {
        setTextOnLabel();
    }

    @Override
    public void keyPressed(KeyEvent k) {
    }
    @Override
    public void keyTyped(KeyEvent k) {
    }

    @Override
    public void itemStateChanged(ItemEvent i) {
        setTextOnLabel();
    }
    @Override
    public void mouseEntered(MouseEvent m) {
        label.setForeground(Color.red);
    }
    @Override
    public void mouseExited(MouseEvent m) {
        label.setForeground(Color.black);
    }
    @Override
    public void mouseClicked(MouseEvent m) {
    }
    @Override
    public void mousePressed(MouseEvent m) {
    }
    @Override
    public void mouseReleased(MouseEvent m) {
    }
}

class ShowMoneyFrame {

    public static void main(String args[]) {
        new MoneyFrame();
    }
}

上述代码的 MoneyFrame 类实现了 KeyListener ItemListener MouseListener 三个接口,因此可以监听三种不同类型的事件:
- KeyListener :实现该接口的类必须包含 keyReleased keyPressed keyTyped 三个方法。当我们松开按键时,事件处理线程会调用 keyReleased 方法。在上述代码中, keyReleased 方法调用了 setTextOnLabel 方法,该方法会根据用户在下拉框中选择的选项,将美元转换为英镑或将英镑转换为美元。
- ItemListener :实现该接口的类必须包含 itemStateChanged 方法。当用户在下拉框中选择一个选项时,事件处理线程会调用此方法。在上述代码中,当用户选择“US to UK”或“UK to US”选项时, itemStateChanged 方法会被调用,进而调用 setTextOnLabel 方法。
- MouseListener :实现该接口的类必须包含 mouseEntered mouseExited mouseClicked mousePressed mouseReleased 方法。与实现 ActionListener 不同,实现 MouseListener 时,线程不仅会对鼠标点击做出响应,还会对鼠标的按下、释放等操作做出响应。在上述代码中,当鼠标移入或移出标签时, mouseEntered mouseExited 方法会被调用,从而改变标签文本的颜色。

1.4 代码结构分析

以下是 MoneyFrame 类的代码结构:

class MoneyFrame extends JFrame implements 
              KeyListener, ItemListener, MouseListener {
    variable declarations
    constructor for the MoneyFrame class
    declaration of a method named setTextOnLabel
    all the methods that are required because the class
        implements three interfaces
}

MoneyFrame 类的构造函数中,添加了四个组件到新的窗口中:
- 标签 :用于显示货币符号,如美元符号。
- 文本框 :用户可以在其中输入金额。
- 另一个标签 :用于显示转换后的货币金额。
- 下拉框 :用户可以选择转换方向,如“US to UK”或“UK to US”。

1.5 内类的创建

在 Java 中,我们可以在一个类内部定义另一个类,这种类被称为内类。例如,以下是一个包含内类的示例代码:

import java.awt.FlowLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.util.Random;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JTextField;

class GameFrame extends JFrame {
   private static final long serialVersionUID = 1L;
   int randomNumber = new Random().nextInt(10) + 1;
   int numGuesses = 0;
   JTextField textField = new JTextField(5);
   JButton button = new JButton("Guess");
   JLabel label = new JLabel(numGuesses + " guesses");

   public GameFrame() {
      setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
      setLayout(new FlowLayout());
      add(textField);
      add(button);
      add(label);
      button.addActionListener(new MyActionListener());
      pack();
      setVisible(true);
   }

   class MyActionListener implements ActionListener {
      @Override
      public void actionPerformed(ActionEvent e) {
         String textFieldText = textField.getText();
         if (Integer.parseInt(textFieldText) == randomNumber) {
            button.setEnabled(false);
            textField.setText(textField.getText() + " Yes!");
            textField.setEnabled(false);
         } else {
            textField.setText("");
            textField.requestFocus();
         }
         numGuesses++;
         String guessWord = 
             (numGuesses == 1) ? " guess" : " guesses";
         label.setText(numGuesses + guessWord);
      }
   }
}

在上述代码中, MyActionListener 类是一个内类。内类与其他类类似,但在内类的代码中,我们可以引用外部类的字段。例如, MyActionListener 类中的多个语句使用了 textField 名称,而 textField 是在外部的 GameFrame 类中定义的。

如果一个内类只被使用一次,我们可以使用匿名内类来简化代码。以下是使用匿名内类的示例代码:

import java.awt.FlowLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.util.Random;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JTextField;

class GameFrame extends JFrame {
   private static final long serialVersionUID = 1L;
   int randomNumber = new Random().nextInt(10) + 1;
   int numGuesses = 0;
   JTextField textField = new JTextField(5);
   JButton button = new JButton("Guess");
   JLabel label = new JLabel(numGuesses + " guesses");

   public GameFrame() {
      setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
      setLayout(new FlowLayout());
      add(textField);
      add(button);
      add(label);
      button.addActionListener(new ActionListener() {
         @Override
         public void actionPerformed(ActionEvent e) {
            String textFieldText = textField.getText();
            if (Integer.parseInt(textFieldText) == randomNumber) {
               button.setEnabled(false);
               textField.setText(textField.getText() + " Yes!");
               textField.setEnabled(false);
            } else {
               textField.setText("");
               textField.requestFocus();
            }
            numGuesses++;
            String guessWord = 
                (numGuesses == 1) ? " guess" : " guesses";
            label.setText(numGuesses + guessWord);
         }
      });
      pack();
      setVisible(true);
   }
}

内类非常适合用于事件处理,如上述示例中的 actionPerformed 方法。不过,编写匿名内类时,需要注意括号、花括号和缩进的使用。建议初学者先编写不包含内类的代码,等熟悉后再尝试使用内类。

2. Java 小程序开发

2.1 Java 小程序简介

Java 小程序(Applet)是一种可以嵌入到网页浏览器窗口中的 Java 程序。它在网页上有自己的矩形区域,能够显示图形、展示图像、实现动画效果、响应用户输入等。以下是一个简单的 Java 小程序示例:

import javax.swing.JApplet;

public class SimpleApplet extends JApplet {
    private static final long serialVersionUID = 1L;
    public void init() {
        setContentPane(new DummiesPanel());
    }
}

import javax.swing.JPanel;
import java.awt.Font;
import java.awt.Graphics;

class DummiesPanel extends JPanel {
    private static final long serialVersionUID = 1L;
    public void paint(Graphics myGraphics) {
       myGraphics.drawRect(50, 60, 220, 75);
       myGraphics.setFont(new Font("Dialog", Font.BOLD, 24));
       myGraphics.drawString("Java For Dummies", 55, 100);
   }
}

要运行上述小程序,我们不需要执行 main 方法,而是需要运行一个网页浏览器,并让浏览器访问包含该小程序引用的 HTML 文件。以下是一个简单的 HTML 文件示例:

<applet code=SimpleApplet width=350 height=200></applet>

2.2 小程序的方法调用

小程序没有 main 方法,因为它不是一个完整的程序,而是一个包含方法的类,这些方法由网页浏览器直接或间接调用。例如,在上述代码中,浏览器会调用 SimpleApplet 类的 init 方法,该方法通过 setContentPane 方法引入 DummiesPanel 类的代码。同时,浏览器会自动调用 DummiesPanel 类的 paint 方法,该方法用于告诉浏览器如何在屏幕上绘制小程序。

2.3 小程序类的访问权限

需要注意的是,任何继承自 JApplet 的类都必须是 public 类。如果创建的小程序类不是 public 类,浏览器在调用该类的方法时会出现“Applet not inited”或“Loading Java Applet Failed”错误。这是因为浏览器不太可能与小程序处于同一个包中,而只有 public 类的方法才能被不同包中的代码调用。

2.4 Java API 的使用

在上述 DummiesPanel 类的代码中,使用了几个有趣的 Java API 方法:
- drawRect :用于绘制一个未填充的矩形。在上述代码中,矩形的左上角坐标为 (50, 60) ,右下角坐标相对于左上角的偏移量为 (220, 75)
- Font 类 :用于描述字符字体的特征。在上述代码中,创建了一个加粗、24 磅的 Dialog 字体。
- drawString :用于在面板上绘制字符串。在上述代码中,字符串“Java For Dummies”的左下角坐标为 (55, 100)

2.5 小程序动画的实现

以下是一个实现动画效果的小程序示例,该小程序模拟了一个里程表的变化:

import javax.swing.JApplet;
import javax.swing.Timer;
import java.awt.Color;
import java.awt.event.ActionListener;
import java.awt.event.ActionEvent;

public class Odometer extends JApplet implements ActionListener {
    private static final long serialVersionUID = 1L;
    Timer timer;
    public void init() {
        OdometerPanel panel = new OdometerPanel();
        panel.setBackground(Color.white);
        setContentPane(panel);
    }
    public void start() {
        if (timer == null) {
            timer = new Timer(100, this);
            timer.start();
        } else {
            timer.restart();
        }
    }
    public void stop() {
        if (timer != null) {
            timer.stop();
            timer = null;
        }
    }
    public void actionPerformed(ActionEvent e) {
        repaint();
    }
}

import javax.swing.JPanel;
import java.awt.Font;
import java.awt.Graphics;

class OdometerPanel extends JPanel {
    private static final long serialVersionUID = 1L;
    long hitCount = 239472938472L;
    public void paint(Graphics myGraphics) {
        myGraphics.setFont(new Font("Monospaced", Font.PLAIN, 24));
        myGraphics.drawString("You are visitor number " + 
             Long.toString(hitCount++), 50, 50);
    }
}

要显示上述小程序,我们可以使用以下 HTML 文件:

<applet code=Odometer width=600 height=200></applet>

2.6 小程序的标准方法

小程序有几个标准方法,这些方法会被网页浏览器自动调用:
- init :当我们首次访问包含小程序的页面时,浏览器会调用该方法。例如,当我们关闭浏览器后再次访问该页面时, init 方法会再次被调用。
- start :在调用 init 方法后,浏览器会调用 start 方法。如果小程序需要执行一些持续的工作,如动画效果,我们可以在 start 方法中编写相关代码。
- paint :在调用 start 方法后,浏览器会调用 paint 方法,该方法用于在屏幕上绘制小程序。浏览器可能会多次调用 paint 方法,例如当我们用其他窗口覆盖部分浏览器窗口,或者缩小浏览器窗口导致小程序部分隐藏,之后再恢复时,浏览器会再次调用 paint 方法。
- stop :当小程序的工作需要停止时,浏览器会调用 stop 方法。例如,当我们点击链接离开包含小程序的页面时, stop 方法会被调用。当我们再次访问该页面时, start 方法会再次被调用。

2.7 小程序动画的实现原理

上述里程表小程序使用了一个标准的动画实现公式:
- 小程序实现了 ActionListener 接口。
- start 方法创建了一个 Timer 对象,该对象每 100 毫秒触发一次事件。当定时器触发事件时,会调用 actionPerformed 方法。
- actionPerformed 方法调用 repaint 方法,该方法会间接调用 OdometerPanel 类的 paint 方法,从而更新屏幕上显示的内容。
- 当浏览器调用 stop 方法时,定时器会停止并被置为 null

如果我们想要在自己的小程序中实现动画效果,可以复制上述代码,并将 init paint 方法替换为自己的代码。在 init 方法中,我们可以编写小程序的初始化代码,如设置面板的属性等;在 paint 方法中,我们可以编写绘制小程序内容的代码。

通过以上内容,我们详细介绍了 Java 事件处理以及小程序开发的相关知识,希望这些内容能帮助你更好地掌握 Java 编程。

3. 事件处理与小程序开发总结

3.1 事件处理总结

在事件处理方面,我们学习了多种响应事件的方法。通过判断按钮点击对象,使用 e.getSource() 可以准确确认被点击的按钮。对于 serialVersionUID ,它能在对象传输时避免版本冲突,除非对类代码进行不兼容更改,否则不要随意修改其值。

响应非按钮点击事件时,以 MoneyFrame 类为例,实现不同接口可以监听不同类型的事件:
| 接口名称 | 必须实现的方法 | 事件触发情况 | 作用 |
| ---- | ---- | ---- | ---- |
| KeyListener | keyReleased、keyPressed、keyTyped | 按键释放、按下、输入时 | 根据用户输入和选择进行货币转换 |
| ItemListener | itemStateChanged | 下拉框选项改变时 | 根据选择更新转换结果 |
| MouseListener | mouseEntered、mouseExited、mouseClicked、mousePressed、mouseReleased | 鼠标移入、移出、点击、按下、释放时 | 改变标签文本颜色 |

内类的使用为事件处理提供了便利。内类可以引用外部类的字段,当只使用一次时,还可以使用匿名内类简化代码。不过编写匿名内类时要注意括号、花括号和缩进。

3.2 小程序开发总结

小程序开发方面,Java 小程序是嵌入网页浏览器的 Java 程序,通过网页浏览器调用其方法来实现各种功能。以下是小程序开发的关键要点总结:
- 基本结构 :继承 JApplet 类,实现 init start paint stop 等方法。
- 访问权限 :继承 JApplet 的类必须是 public 类,否则浏览器无法调用其方法。
- API 使用 :使用 drawRect Font drawString 等 Java API 方法来实现图形绘制和文本显示。
- 动画实现 :实现 ActionListener 接口,使用 Timer 对象触发事件,调用 repaint 方法更新屏幕内容。

3.3 开发流程建议

为了更好地进行 Java 事件处理和小程序开发,以下是一个开发流程建议:

graph LR
    A[需求分析] --> B[设计架构]
    B --> C[编写代码]
    C --> D[测试调试]
    D --> E[优化改进]
    E --> F[部署上线]
  • 需求分析 :明确要实现的功能,如事件响应类型、小程序的展示效果等。
  • 设计架构 :根据需求设计类的结构,确定需要实现的接口和方法。
  • 编写代码 :按照设计架构编写代码,注意代码的规范性和可读性。
  • 测试调试 :对代码进行测试,检查是否能正常响应事件和展示小程序。
  • 优化改进 :根据测试结果对代码进行优化,如提高性能、改进用户体验等。
  • 部署上线 :将代码部署到合适的环境中,供用户使用。

3.4 学习建议

对于初学者来说,建议先从简单的代码入手,如不包含内类的普通 Java 类和简单的小程序示例。在掌握基本概念和方法后,再逐步尝试使用内类和实现复杂的功能。同时,要多阅读 Java API 文档,了解更多的方法和类,以便在开发中灵活运用。

通过不断实践和学习,相信大家能够熟练掌握 Java 事件处理和小程序开发技术,开发出更加优秀的 Java 程序。

评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符  | 博主筛选后可见
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值