本文目录导读:

我来通过一个简单的计算器案例,系统地讲解Java事件监听机制,这个案例会从最基础的版本逐步扩展到更完善的实现。
最基础版本(理解核心概念)
import javax.swing.*;
import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
public class CalculatorV1 {
public static void main(String[] args) {
// 创建窗口
JFrame frame = new JFrame("简易计算器 V1");
frame.setSize(300, 200);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
// 创建组件
JTextField num1Field = new JTextField(10);
JTextField num2Field = new JTextField(10);
JButton addButton = new JButton("相加");
JLabel resultLabel = new JLabel("结果: ");
// 设置布局
JPanel panel = new JPanel();
panel.add(new JLabel("数字1:"));
panel.add(num1Field);
panel.add(new JLabel("数字2:"));
panel.add(num2Field);
panel.add(addButton);
panel.add(resultLabel);
// 核心:注册事件监听器
// ActionListener是一个接口,我们通过匿名内部类实现它
addButton.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
try {
// 获取输入
double num1 = Double.parseDouble(num1Field.getText());
double num2 = Double.parseDouble(num2Field.getText());
// 进行计算
double result = num1 + num2;
// 显示结果
resultLabel.setText("结果: " + result);
} catch (NumberFormatException ex) {
resultLabel.setText("输入格式错误!");
}
}
});
frame.add(panel);
frame.setVisible(true);
}
}
使用内部类实现(更好的组织代码)
import javax.swing.*;
import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
public class CalculatorV2 {
private JFrame frame;
private JTextField num1Field;
private JTextField num2Field;
private JLabel resultLabel;
public CalculatorV2() {
initializeGUI();
addEventListeners();
}
private void initializeGUI() {
frame = new JFrame("简易计算器 V2");
frame.setSize(400, 200);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
num1Field = new JTextField(10);
num2Field = new JTextField(10);
resultLabel = new JLabel("结果: ");
// 创建多个按钮
JButton addBtn = new JButton("+");
JButton subtractBtn = new JButton("-");
JButton multiplyBtn = new JButton("×");
JButton divideBtn = new JButton("÷");
JPanel panel = new JPanel(new GridLayout(3, 1));
// 输入面板
JPanel inputPanel = new JPanel();
inputPanel.add(new JLabel("数字1:"));
inputPanel.add(num1Field);
inputPanel.add(new JLabel("数字2:"));
inputPanel.add(num2Field);
// 按钮面板
JPanel buttonPanel = new JPanel();
buttonPanel.add(addBtn);
buttonPanel.add(subtractBtn);
buttonPanel.add(multiplyBtn);
buttonPanel.add(divideBtn);
// 结果面板
JPanel resultPanel = new JPanel();
resultPanel.add(resultLabel);
panel.add(inputPanel);
panel.add(buttonPanel);
panel.add(resultPanel);
frame.add(panel);
// 使用内部类作为事件监听器
CalculatorActionListener listener = new CalculatorActionListener();
addBtn.addActionListener(listener);
subtractBtn.addActionListener(listener);
multiplyBtn.addActionListener(listener);
divideBtn.addActionListener(listener);
}
// 内部类实现事件监听器 - 更好的代码组织
private class CalculatorActionListener implements ActionListener {
@Override
public void actionPerformed(ActionEvent e) {
try {
double num1 = Double.parseDouble(num1Field.getText());
double num2 = Double.parseDouble(num2Field.getText());
double result = 0;
// 根据按钮的文本来确定操作
String command = e.getActionCommand();
switch(command) {
case "+":
result = num1 + num2;
break;
case "-":
result = num1 - num2;
break;
case "×":
result = num1 * num2;
break;
case "÷":
if (num2 != 0) {
result = num1 / num2;
} else {
resultLabel.setText("不能除0!");
return;
}
break;
}
resultLabel.setText("结果: " + result);
} catch (NumberFormatException ex) {
resultLabel.setText("输入格式错误!");
}
}
}
private void addEventListeners() {
// 可以添加键盘事件等
}
public void show() {
frame.setVisible(true);
}
public static void main(String[] args) {
new CalculatorV2().show();
}
}
完整功能版本(使用Lambda表达式)
import javax.swing.*;
import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.util.HashMap;
import java.util.Map;
import java.util.function.BinaryOperator;
public class CalculatorV3 {
private JFrame frame;
private JTextField displayField;
private JLabel resultLabel;
private String currentOperator = "";
private double firstNumber = 0;
private boolean isNewNumber = true;
// 操作映射 - 使用Lambda表达式
private Map<String, BinaryOperator<Double>> operations = new HashMap<>();
public CalculatorV3() {
// 初始化操作映射 - 这里展示了Lambda表达式的简洁性
operations.put("+", (a, b) -> a + b);
operations.put("-", (a, b) -> a - b);
operations.put("*", (a, b) -> a * b);
operations.put("/", (a, b) -> b != 0 ? a / b : Double.NaN);
initializeGUI();
setupEventListeners();
}
private void initializeGUI() {
frame = new JFrame("科学计算器 V3");
frame.setSize(300, 400);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
displayField = new JTextField();
displayField.setEditable(false);
displayField.setFont(new Font("Arial", Font.BOLD, 20));
displayField.setHorizontalAlignment(JTextField.RIGHT);
resultLabel = new JLabel(" ", SwingConstants.RIGHT);
resultLabel.setFont(new Font("Arial", Font.PLAIN, 14));
// 创建按钮
String[][] buttonLabels = {
{"7", "8", "9", "/"},
{"4", "5", "6", "*"},
{"1", "2", "3", "-"},
{"0", ".", "=", "+"},
{"C", "CE", "←", "±"}
};
JPanel buttonPanel = new JPanel(new GridLayout(5, 4, 2, 2));
for (String[] row : buttonLabels) {
for (String label : row) {
JButton button = new JButton(label);
button.setFont(new Font("Arial", Font.PLAIN, 16));
buttonPanel.add(button);
}
}
// 布局
frame.setLayout(new BorderLayout());
JPanel topPanel = new JPanel(new GridLayout(2, 1));
topPanel.add(displayField);
topPanel.add(resultLabel);
frame.add(topPanel, BorderLayout.NORTH);
frame.add(buttonPanel, BorderLayout.CENTER);
}
private void setupEventListeners() {
// 获取所有按钮
Component[] components = ((JPanel)frame.getContentPane()
.getComponent(1)).getComponents();
for (Component comp : components) {
if (comp instanceof JButton) {
JButton button = (JButton) comp;
String text = button.getText();
// 使用Lambda表达式注册事件监听器
button.addActionListener(e -> handleButtonClick(e));
}
}
// 也可以使用键盘快捷键
KeyboardFocusManager.getCurrentKeyboardFocusManager()
.addKeyEventDispatcher(e -> {
if (e.getID() == KeyEvent.KEY_PRESSED) {
char keyChar = e.getKeyChar();
if (Character.isDigit(keyChar) ||
"+-*/.=".indexOf(keyChar) >= 0) {
handleKeyInput(String.valueOf(keyChar));
return true;
}
}
return false;
});
}
private void handleButtonClick(ActionEvent e) {
JButton source = (JButton) e.getSource();
handleInput(source.getText());
}
private void handleKeyInput(String input) {
handleInput(input);
}
private void handleInput(String input) {
switch(input) {
case "C":
clearAll();
break;
case "CE":
clearEntry();
break;
case "←":
backspace();
break;
case "±":
toggleSign();
break;
case "=":
calculate();
break;
case "+": case "-": case "*": case "/":
setOperator(input);
break;
default: // 数字和小数点
appendDigit(input);
break;
}
}
private void appendDigit(String digit) {
if (isNewNumber) {
displayField.setText(digit);
isNewNumber = false;
} else {
String current = displayField.getText();
if (digit.equals(".") && current.contains(".")) {
return; // 防止多个小数点
}
displayField.setText(current + digit);
}
}
private void setOperator(String operator) {
if (!displayField.getText().isEmpty()) {
firstNumber = Double.parseDouble(displayField.getText());
currentOperator = operator;
isNewNumber = true;
resultLabel.setText(firstNumber + " " + operator);
}
}
private void calculate() {
if (!currentOperator.isEmpty() && !displayField.getText().isEmpty()) {
double secondNumber = Double.parseDouble(displayField.getText());
// 使用Lambda表达式定义的操作
BinaryOperator<Double> operation = operations.get(currentOperator);
if (operation != null) {
double result = operation.apply(firstNumber, secondNumber);
if (Double.isNaN(result)) {
displayField.setText("错误: 除数不能为0");
} else {
displayField.setText(String.valueOf(result));
resultLabel.setText(firstNumber + " " +
currentOperator + " " + secondNumber + " =");
}
}
currentOperator = "";
isNewNumber = true;
}
}
private void clearAll() {
displayField.setText("");
resultLabel.setText("");
currentOperator = "";
firstNumber = 0;
isNewNumber = true;
}
private void clearEntry() {
displayField.setText("");
isNewNumber = true;
}
private void backspace() {
String text = displayField.getText();
if (text.length() > 0) {
displayField.setText(text.substring(0, text.length() - 1));
}
}
private void toggleSign() {
if (!displayField.getText().isEmpty()) {
double value = Double.parseDouble(displayField.getText());
displayField.setText(String.valueOf(-value));
}
}
public void show() {
frame.setVisible(true);
}
public static void main(String[] args) {
// 使用SwingUtilities确保线程安全
SwingUtilities.invokeLater(() -> {
new CalculatorV3().show();
});
}
}
关键概念总结
事件监听机制的三个核心组件:
// 1. 事件源 (Event Source) - 谁触发事件
JButton button = new JButton("点击我");
// 2. 事件对象 (Event Object) - 事件信息
// ActionEvent包含了事件的相关信息
// 3. 事件监听器 (Event Listener) - 如何处理事件
// 实现特定接口的对象
button.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
// 事件处理代码
}
});
五种监听器实现方式:
// 方式1: 匿名内部类 (最常用)
button.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
System.out.println("按钮被点击");
}
});
// 方式2: Lambda表达式 (Java 8+)
button.addActionListener(e -> System.out.println("按钮被点击"));
// 方式3: 方法引用
button.addActionListener(this::handleClick);
// 方式4: 内部类
class MyListener implements ActionListener {
@Override
public void actionPerformed(ActionEvent e) {
handleClick(e);
}
}
// 方式5: 外部类
button.addActionListener(new ExternalActionListener());
事件处理的最佳实践:
// 1. 线程安全 - 使用SwingUtilities
SwingUtilities.invokeLater(() -> {
// UI更新代码
});
// 2. 避免长时间操作在事件线程
SwingWorker<Void, Void> worker = new SwingWorker<Void, Void>() {
@Override
protected Void doInBackground() {
// 耗时操作
return null;
}
@Override
protected void done() {
// 更新UI
}
};
worker.execute();
// 3. 使用适配器类减少代码
window.addWindowListener(new WindowAdapter() {
@Override
public void windowClosing(WindowEvent e) {
// 只重写需要的方法
}
});
这个计算器案例从最简单的版本开始,逐步增加了功能并展示了不同的事件处理方式,通过实践这些代码,你可以深入理解Java事件监听机制的工作原理和应用方式。