0

Series Java Swing Bài 21: JMenu, JMenuBar, JMenuItem - Xây dựng thanh menu chuẩn

Bất kỳ phần mềm Desktop chuyên nghiệp nào (từ Notepad, MS Word đến IntelliJ) đều sở hữu một thanh menu ngang ở sát mép trên cùng của cửa sổ. Trong Java Swing, hệ thống Menu được xây dựng dựa trên cấu trúc phân cấp chặt chẽ gồm 3 thành phần chính:

  1. JMenuBar: Thanh ngang gốc (đặt ở trên cùng cửa sổ).

  2. JMenu: Các danh mục lớn xổ xuống (Ví dụ: File, Edit, View, Help). Một JMenuBar chứa nhiều JMenu.

  3. JMenuItem: Các nút bấm hành động cụ thể nằm bên trong danh mục (Ví dụ: New, Open, Save, Exit). Một JMenu chứa nhiều JMenuItem.

1. Khởi tạo và gắn MenuBar vào JFrame

Điểm đặc biệt nhất của JMenuBar là bạn không dùng phương thức add() của các Layout Manager để đưa nó lên màn hình. JFrame có sẵn một "ngăn chứa VIP" dành riêng cho thanh menu thông qua phương thức setJMenuBar().

Java

// 1. Tạo thanh menu
JMenuBar menuBar = new JMenuBar();

// 2. Gắn thanh menu vào JFrame (Nó sẽ tự động bám dính lên trên cùng)
frame.setJMenuBar(menuBar);

2. Tổ chức cấu trúc Menu và Dấu phân cách (Separator)

Để thêm các mục vào menu, bạn đi theo logic từ ngoài vào trong: JMenu thêm vào JMenuBar, và JMenuItem thêm vào JMenu.

Để phân tách các nhóm chức năng (ví dụ: Tách nhóm Open/Save ra khỏi nút Exit), Swing cung cấp một vạch kẻ ngang gọi là Separator.

Java

// Tạo danh mục lớn
JMenu menuFile = new JMenu("File");
menuBar.add(menuFile); // Đưa vào MenuBar

// Tạo các nút hành động con
JMenuItem itemNew = new JMenuItem("New");
JMenuItem itemSave = new JMenuItem("Save");
JMenuItem itemExit = new JMenuItem("Exit");

// Đưa các nút con vào danh mục File
menuFile.add(itemNew);
menuFile.add(itemSave);

// Chèn vạch kẻ ngang phân cách
menuFile.addSeparator(); 

menuFile.add(itemExit);

3. Nâng tầm chuyên nghiệp: Phím tắt (Shortcuts)

Một thanh menu không có phím tắt là một thanh menu "chết". Swing hỗ trợ 2 loại phím tắt tiêu chuẩn:

Mnemonics (Phím gạch chân)

Dùng kết hợp với phím Alt. Khi bạn gán Mnemonic, Swing sẽ tự động gạch chân chữ cái đó trên giao diện.

Java

// Gán Mnemonic bằng ký tự 'F'
// Người dùng ấn Alt + F sẽ mở menu File
menuFile.setMnemonic(KeyEvent.VK_F); 

Accelerators (Tổ hợp phím nóng)

Gắn thẳng một tổ hợp phím (Ví dụ: Ctrl + S, Ctrl + Shift + S) để thực thi lệnh ngay lập tức mà không cần mở menu ra.

Java

// Gán phím tắt Ctrl + S cho nút Save
// KeyEvent.CTRL_DOWN_MASK đại diện cho phím Ctrl trên Windows/Linux
itemSave.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_S, KeyEvent.CTRL_DOWN_MASK));

(Mẹo: Nếu phần mềm chạy trên macOS, phím tắt tiêu chuẩn phải là Command + S. Để Swing tự động nhận diện hệ điều hành và gán phím tương ứng (Ctrl cho Win, Cmd cho Mac), hãy dùng Toolkit.getDefaultToolkit().getMenuShortcutKeyMaskEx() thay cho CTRL_DOWN_MASK).

4. Các loại Menu Item đặc biệt

Ngoài nút bấm thông thường, Swing cung cấp các Item có khả năng lưu trữ trạng thái (giống CheckBox và RadioButton):

  • JCheckBoxMenuItem: Tích chọn/bỏ chọn một tính năng (Ví dụ: Chế độ Word Wrap trong Notepad).

  • Menu lồng Menu (Sub-menu): Bản thân một JMenu có thể được add vào bên trong một JMenu khác để tạo ra danh mục đa cấp.

Java

// Tạo nút tích chọn
JCheckBoxMenuItem chkWordWrap = new JCheckBoxMenuItem("Word Wrap");
chkWordWrap.setSelected(true); // Mặc định bật

5. Source Code Thực Chiến: Ứng dụng Notepad Mini

Đoạn code dưới đây tích hợp toàn bộ kiến thức để tạo ra một khung thanh menu giống hệt phần mềm Notepad mặc định của Windows.

Java

import javax.swing.*;
import java.awt.*;
import java.awt.event.KeyEvent;

public class MenuBarDemo extends JFrame {

    public MenuBarDemo() {
        setTitle("Notepad Mini - JMenuBar Demo");
        setSize(600, 400);
        setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        setLocationRelativeTo(null);

        // Thêm một vùng soạn thảo để khung nhìn chân thực hơn
        JTextArea textArea = new JTextArea();
        add(new JScrollPane(textArea), BorderLayout.CENTER);

        // ==========================================
        // 1. KHỞI TẠO MENU BAR
        // ==========================================
        JMenuBar menuBar = new JMenuBar();

        // ==========================================
        // 2. XÂY DỰNG MENU "FILE"
        // ==========================================
        JMenu menuFile = new JMenu("File");
        menuFile.setMnemonic(KeyEvent.VK_F); // Alt + F

        JMenuItem itemNew = new JMenuItem("New", new ImageIcon("icons/new.png")); // Có thể chèn Icon
        itemNew.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_N, Toolkit.getDefaultToolkit().getMenuShortcutKeyMaskEx()));

        JMenuItem itemSave = new JMenuItem("Save");
        itemSave.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_S, Toolkit.getDefaultToolkit().getMenuShortcutKeyMaskEx()));

        JMenuItem itemExit = new JMenuItem("Exit");
        // Gán logic tắt phần mềm cho nút Exit
        itemExit.addActionListener(e -> System.exit(0));

        menuFile.add(itemNew);
        menuFile.add(itemSave);
        menuFile.addSeparator(); // Dấu phân cách
        menuFile.add(itemExit);

        // ==========================================
        // 3. XÂY DỰNG MENU "VIEW" VÀ SUB-MENU
        // ==========================================
        JMenu menuView = new JMenu("View");
        menuView.setMnemonic(KeyEvent.VK_V); // Alt + V

        JCheckBoxMenuItem itemWordWrap = new JCheckBoxMenuItem("Word Wrap");
        itemWordWrap.setSelected(true);
        // Logic khi bật/tắt Word Wrap
        itemWordWrap.addActionListener(e -> {
            textArea.setLineWrap(itemWordWrap.isSelected());
        });

        // Tạo một Sub-menu (Menu con)
        JMenu subMenuZoom = new JMenu("Zoom");
        JMenuItem itemZoomIn = new JMenuItem("Zoom In");
        JMenuItem itemZoomOut = new JMenuItem("Zoom Out");
        subMenuZoom.add(itemZoomIn);
        subMenuZoom.add(itemZoomOut);

        menuView.add(itemWordWrap);
        menuView.addSeparator();
        menuView.add(subMenuZoom); // Add Menu vào Menu để làm Sub-menu

        // ==========================================
        // 4. RÁP VÀO MENU BAR VÀ GẮN LÊN FRAME
        // ==========================================
        menuBar.add(menuFile);
        menuBar.add(menuView);

        // Gắn thanh Menu lên JFrame (Không dùng add())
        setJMenuBar(menuBar);
    }

    public static void main(String[] args) {
        SwingUtilities.invokeLater(() -> new MenuBarDemo().setVisible(true));
    }
}

All rights reserved

Viblo
Hãy đăng ký một tài khoản Viblo để nhận được nhiều bài viết thú vị hơn.
Đăng kí