Series Java Swing Bài 25: ActionListener - Bắt sự kiện click nút bấm và phím Enter
Chào mừng bạn bước vào Phần 5: Quản lý sự kiện (Event Handling). Từ Bài 1 đến Bài 24, chúng ta đã học cách "vẽ" ra một giao diện đẹp mắt. Nhưng nếu không có sự kiện, giao diện đó chỉ là một bức tranh tĩnh vô hồn.
Trong Java Swing, cơ chế xử lý sự kiện hoạt động theo mô hình Delegation Event Model (Ủy thác sự kiện). Nghĩa là Component (như nút bấm) sẽ sinh ra sự kiện, nhưng nó không tự xử lý mà "ủy thác" (giao việc) cho một đối tượng khác gọi là Listener (Bộ lắng nghe).
Bộ lắng nghe phổ biến nhất, quyền lực nhất chính là ActionListener.
1. Bản chất của ActionListener
ActionListener là một Interface chỉ chứa duy nhất một phương thức: actionPerformed(ActionEvent e). Nó được thiết kế để bắt các "hành động dứt khoát" từ người dùng, phổ biến nhất là 3 trường hợp:
-
Click chuột trái vào
JButton. -
Gõ phím Enter khi đang nhập liệu trong
JTextFieldhoặcJPasswordField. -
Click chọn một mục trong
JMenuItem(Thanh Menu).
Cú pháp viết code (Trước và sau Java 8)
Cách 1: Cổ điển (Anonymous Inner Class) - Code khá dài dòng, bạn sẽ gặp nhiều trong các giáo trình cũ.
Java
btnSubmit.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
System.out.println("Nút đã được bấm!");
}
});
Cách 2: Hiện đại (Lambda Expression - từ Java 8 trở lên) - Rất ngắn gọn và khuyên dùng 100% trong thực tế.
Java
btnSubmit.addActionListener(e -> {
System.out.println("Nút đã được bấm!");
});
2. Xử lý nhiều nút bấm cùng lúc (Event Source)
Giả sử ứng dụng của bạn có một chiếc máy tính bỏ túi với 10 nút bấm (từ 0 đến 9). Việc viết 10 hàm Lambda riêng biệt cho 10 nút là điều ngốc nghếch. Thay vào đó, chúng ta sẽ gán chung 1 Listener cho cả 10 nút, và sử dụng đối tượng ActionEvent e để phân biệt xem nút nào vừa bị click.
Có 2 cách để phân biệt nguồn gốc sự kiện:
Cách 1: Dùng e.getSource() (So sánh đối tượng)
Trả về chính xác Component vừa phát ra sự kiện. Bạn dùng toán tử == để kiểm tra.
Java
JButton btnAdd = new JButton("Thêm");
JButton btnEdit = new JButton("Sửa");
ActionListener sharedListener = e -> {
if (e.getSource() == btnAdd) {
System.out.println("Thực hiện lệnh Thêm");
} else if (e.getSource() == btnEdit) {
System.out.println("Thực hiện lệnh Sửa");
}
};
btnAdd.addActionListener(sharedListener);
btnEdit.addActionListener(sharedListener);
Cách 2: Dùng e.getActionCommand() (So sánh chuỗi)
Mặc định, lệnh này sẽ trả về chuỗi văn bản (Text) ghi trên nút bấm. Phương pháp này rất mạnh khi bạn dùng vòng lặp để tạo hàng chục nút bấm.
Java
ActionListener numberListener = e -> {
String number = e.getActionCommand();
System.out.println("Bạn vừa bấm số: " + number);
};
// Tạo nhanh 3 nút bấm và gán chung 1 sự kiện
JButton btn1 = new JButton("1"); btn1.addActionListener(numberListener);
JButton btn2 = new JButton("2"); btn2.addActionListener(numberListener);
JButton btn3 = new JButton("3"); btn3.addActionListener(numberListener);
(Lưu ý: Bạn có thể thay đổi chuỗi trả về này bằng hàm btn.setActionCommand("Mã_Bí_Mật");)
3. Tuyệt chiêu: Bắt phím Enter trong JTextField
Khi người dùng điền xong Form đăng nhập (gõ xong mật khẩu), hành vi tự nhiên nhất của họ là gõ phím Enter trên bàn phím, thay vì phải cầm chuột lên click vào nút "Đăng nhập".
Nhiều người mới học lầm tưởng phải dùng KeyListener để bắt phím Enter. Không cần thiết! Bản thân JTextField và JPasswordField đã được tích hợp sẵn ActionListener. Khi ô nhập liệu đang được trỏ chuột (Focus) mà người dùng gõ phím Enter, nó sẽ tự động kích hoạt sự kiện này.
Java
JTextField txtSearch = new JTextField(20);
// Sự kiện này kích hoạt KHI GÕ ENTER trong ô text
txtSearch.addActionListener(e -> {
String keyword = txtSearch.getText();
System.out.println("Đang tìm kiếm từ khóa: " + keyword);
});
4. Source Code Thực Chiến: Form Đăng Nhập Hoàn Hảo
Đoạn code dưới đây kết hợp toàn bộ kiến thức để tạo ra một luồng xử lý chuyên nghiệp: Bạn có thể click nút "Đăng nhập", HOẶC gõ Enter ở ô Mật khẩu, hệ thống đều chạy chung một logic xử lý.
Java
import javax.swing.*;
import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.util.Arrays;
public class ActionListenerDemo extends JFrame {
// Khai báo các Component ở cấp class để dùng chung trong các hàm
private JTextField txtUsername;
private JPasswordField txtPassword;
private JButton btnLogin;
private JButton btnCancel;
public ActionListenerDemo() {
setTitle("Đăng nhập hệ thống - Bài 25");
setSize(350, 200);
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
setLocationRelativeTo(null);
setLayout(new GridBagLayout());
GridBagConstraints gbc = new GridBagConstraints();
gbc.insets = new Insets(5, 5, 5, 5);
// ==========================================
// KHỞI TẠO GIAO DIỆN
// ==========================================
gbc.gridx = 0; gbc.gridy = 0; add(new JLabel("Tài khoản:"), gbc);
gbc.gridx = 1; gbc.gridy = 0;
txtUsername = new JTextField(15);
add(txtUsername, gbc);
gbc.gridx = 0; gbc.gridy = 1; add(new JLabel("Mật khẩu:"), gbc);
gbc.gridx = 1; gbc.gridy = 1;
txtPassword = new JPasswordField(15);
add(txtPassword, gbc);
// Panel chứa 2 nút bấm
JPanel buttonPanel = new JPanel(new FlowLayout(FlowLayout.CENTER));
btnLogin = new JButton("Đăng nhập");
btnCancel = new JButton("Hủy bỏ");
buttonPanel.add(btnLogin);
buttonPanel.add(btnCancel);
gbc.gridx = 0; gbc.gridy = 2; gbc.gridwidth = 2;
add(buttonPanel, gbc);
// ==========================================
// GẮN SỰ KIỆN (ACTION LISTENER)
// ==========================================
// 1. Logic xử lý Đăng nhập được tách ra thành một hàm riêng để tái sử dụng
Runnable performLoginLogic = () -> {
String user = txtUsername.getText();
char[] pass = txtPassword.getPassword();
if ("admin".equals(user) && "123".equals(new String(pass))) {
JOptionPane.showMessageDialog(this, "Đăng nhập thành công!", "Thông báo", JOptionPane.INFORMATION_MESSAGE);
} else {
JOptionPane.showMessageDialog(this, "Sai tài khoản hoặc mật khẩu!", "Lỗi", JOptionPane.ERROR_MESSAGE);
}
Arrays.fill(pass, '0'); // Xóa RAM
};
// 2. Gắn sự kiện cho nút bấm "Đăng nhập"
btnLogin.addActionListener(e -> performLoginLogic.run());
// 3. Gắn sự kiện CHÍNH KHÓA: Khi gõ Enter ở ô Mật Khẩu
txtPassword.addActionListener(e -> performLoginLogic.run());
// (Tùy chọn) Nếu muốn gõ Enter ở ô Tài khoản cũng đăng nhập, mở dòng dưới:
// txtUsername.addActionListener(e -> performLoginLogic.run());
// 4. Gắn sự kiện cho nút Hủy bỏ
btnCancel.addActionListener(e -> {
txtUsername.setText("");
txtPassword.setText("");
txtUsername.requestFocus(); // Đưa con trỏ chuột về lại ô Tài khoản
});
}
public static void main(String[] args) {
SwingUtilities.invokeLater(() -> new ActionListenerDemo().setVisible(true));
}
}
Hãy chạy thử đoạn code, gõ "admin" vào ô tài khoản, "123" vào ô mật khẩu và bấm phím Enter. Bạn sẽ thấy cảm giác thao tác mượt mà như một phần mềm thực thụ.
All rights reserved