0

Series Java Swing Bài 9: BoxLayout và CardLayout: Xếp chồng Component và chuyển đổi màn hình

Trong bài này, chúng ta sẽ khám phá hai Layout Manager giúp bạn xây dựng các giao diện ứng dụng thực tế: BoxLayout (chuyên xếp hàng các thành phần) và CardLayout (chuyên lật trang, chuyển đổi qua lại giữa các màn hình).

1. BoxLayout: Xếp hàng ngang dọc một chiều

Nếu FlowLayout xếp các thành phần từ trái sang phải và tự động rớt dòng khi hết chỗ, thì BoxLayout nghiêm ngặt hơn: Nó ép các thành phần xếp thành một hàng ngang duy nhất hoặc một cột dọc duy nhất, bất chấp việc cửa sổ bị kéo nhỏ lại, các thành phần thà bị che khuất chứ tuyệt đối không rớt dòng.

Các trục (Axis) của BoxLayout

Khi khởi tạo, bạn phải chỉ định trục sắp xếp:

  • BoxLayout.X_AXIS: Xếp từ trái sang phải.

  • BoxLayout.Y_AXIS: Xếp từ trên xuống dưới.

Vũ khí bí mật: Class Box

Sức mạnh thực sự của BoxLayout không nằm ở bản thân nó, mà nằm ở lớp tiện ích Box. Lớp này cung cấp các "khoảng trống vô hình" để bạn chèn vào giữa các Component, giúp căn lề cực kỳ linh hoạt:

  • Box.createRigidArea(new Dimension(w, h)): Tạo một khối khoảng trống cố định (như viên gạch chèn vào giữa 2 nút bấm).

  • Box.createVerticalGlue() / createHorizontalGlue(): Tạo ra một chiếc "lò xo vô hình". Nó sẽ tự động đẩy mút các Component về hai đầu. Rất hữu ích khi bạn muốn có một nút "Đăng xuất" luôn bị đẩy xuống tít dưới cùng của thanh Menu.

2. CardLayout: Ảo thuật gia lật bài

CardLayout hoạt động đúng như tên gọi của nó: Cỗ bài (Card). Bạn có thể xếp chồng hàng tá JPanel (mỗi Panel là một trang màn hình) lên cùng một vị trí. Tuy nhiên, tại một thời điểm, chỉ có lá bài trên cùng (trang hiện tại) được hiển thị, các lá bài khác sẽ bị ẩn đi.

Nguyên lý hoạt động

  1. Khởi tạo CardLayout và gán cho một Container cha (ví dụ JPanel mainPanel).

  2. Nhét các Panel con vào mainPanel kèm theo một cái tên định danh (String).

  3. Dùng lệnh cardLayout.show(mainPanel, "Tên_Định_Danh") để lật tới trang mong muốn.

Ứng dụng thực tế:

  • Làm giao diện cài đặt (Settings) với thanh menu bên trái, nội dung bên phải thay đổi theo menu.

  • Làm trình hướng dẫn cài đặt phần mềm (Wizard) với các nút "Back", "Next".

  • Làm ứng dụng Single Page (SPA) thu nhỏ.

3. Source Code Thực chiến: Kết hợp BoxLayout và CardLayout

Đoạn code dưới đây là một ví dụ kinh điển kết hợp cả 2 Layout này để tạo ra một Giao diện Dashboard có thanh Sidebar điều hướng (Giống như các phần mềm quản lý hiện đại).

  • Bên trái (WEST): Dùng BoxLayout dọc để xếp các nút Menu. Sử dụng Glue để đẩy nút "Đăng xuất" xuống cuối cùng.

  • Ở giữa (CENTER): Dùng CardLayout để chứa 3 màn hình khác nhau. Bấm menu nào, hiển thị màn hình đó.

Java

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

public class DashboardDemo extends JFrame {

    // Khai báo CardLayout và Panel chứa các Card ở cấp toàn cục để dễ gọi trong sự kiện
    private CardLayout cardLayout;
    private JPanel centerCardsPanel;

    public DashboardDemo() {
        setTitle("Phần mềm Quản lý - CardLayout & BoxLayout");
        setSize(600, 400);
        setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        setLocationRelativeTo(null);
        setLayout(new BorderLayout()); // Layout tổng của cửa sổ

        // ==========================================
        // 1. TẠO SIDEBAR (BÊN TRÁI) BẰNG BOXLAYOUT
        // ==========================================
        JPanel sidebarPanel = new JPanel();
        sidebarPanel.setLayout(new BoxLayout(sidebarPanel, BoxLayout.Y_AXIS));
        sidebarPanel.setBackground(new Color(45, 52, 54));
        sidebarPanel.setPreferredSize(new Dimension(150, 0));

        JButton btnHome = createMenuButton("Trang chủ");
        JButton btnProfile = createMenuButton("Hồ sơ");
        JButton btnSettings = createMenuButton("Cài đặt");
        JButton btnLogout = createMenuButton("Đăng xuất");

        // Thêm các nút vào Sidebar kèm khoảng trống (RigidArea và Glue)
        sidebarPanel.add(Box.createRigidArea(new Dimension(0, 20))); // Cách mép trên 20px
        sidebarPanel.add(btnHome);
        sidebarPanel.add(Box.createRigidArea(new Dimension(0, 10))); // Cách nhau 10px
        sidebarPanel.add(btnProfile);
        sidebarPanel.add(Box.createRigidArea(new Dimension(0, 10)));
        sidebarPanel.add(btnSettings);
        
        // CÚ PHÁP QUAN TRỌNG: Lò xo vô hình đẩy nút Đăng xuất xuống đáy
        sidebarPanel.add(Box.createVerticalGlue()); 
        sidebarPanel.add(btnLogout);
        sidebarPanel.add(Box.createRigidArea(new Dimension(0, 20))); // Cách đáy 20px

        // ==========================================
        // 2. TẠO KHU VỰC HIỂN THỊ (Ở GIỮA) BẰNG CARDLAYOUT
        // ==========================================
        cardLayout = new CardLayout();
        centerCardsPanel = new JPanel(cardLayout);

        // Tạo 3 màn hình (Panel) con
        JPanel homePanel = createCardPanel("🏠 Màn hình Trang Chủ", Color.LIGHT_GRAY);
        JPanel profilePanel = createCardPanel("👤 Màn hình Hồ Sơ", new Color(173, 216, 230)); // Xanh nhạt
        JPanel settingsPanel = createCardPanel("⚙️ Màn hình Cài Đặt", new Color(255, 228, 225)); // Hồng nhạt

        // Đưa 3 màn hình vào centerCardsPanel kèm theo "Tên định danh"
        centerCardsPanel.add(homePanel, "CARD_HOME");
        centerCardsPanel.add(profilePanel, "CARD_PROFILE");
        centerCardsPanel.add(settingsPanel, "CARD_SETTINGS");

        // ==========================================
        // 3. XỬ LÝ SỰ KIỆN CLICK MENU -> LẬT TRANG
        // ==========================================
        btnHome.addActionListener(e -> cardLayout.show(centerCardsPanel, "CARD_HOME"));
        btnProfile.addActionListener(e -> cardLayout.show(centerCardsPanel, "CARD_PROFILE"));
        btnSettings.addActionListener(e -> cardLayout.show(centerCardsPanel, "CARD_SETTINGS"));
        btnLogout.addActionListener(e -> System.exit(0));

        // ==========================================
        // 4. RÁP VÀO CỬA SỔ CHÍNH
        // ==========================================
        add(sidebarPanel, BorderLayout.WEST);
        add(centerCardsPanel, BorderLayout.CENTER);
    }

    // Hàm tiện ích: Tạo nút bấm giao diện phẳng cho menu
    private JButton createMenuButton(String text) {
        JButton btn = new JButton(text);
        btn.setMaximumSize(new Dimension(150, 40)); // Ép chiều rộng lấp đầy Sidebar
        btn.setAlignmentX(Component.CENTER_ALIGNMENT);
        btn.setFocusPainted(false);
        return btn;
    }

    // Hàm tiện ích: Tạo nhanh một màn hình (Panel) với màu nền và Text ở giữa
    private JPanel createCardPanel(String text, Color bgColor) {
        JPanel panel = new JPanel(new GridBagLayout()); // Tạm dùng để căn giữa Text
        panel.setBackground(bgColor);
        JLabel label = new JLabel(text);
        label.setFont(new Font("Arial", Font.BOLD, 24));
        panel.add(label);
        return panel;
    }

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

Hãy copy và chạy đoạn code trên, bạn sẽ thấy sự mượt mà khi chuyển đổi qua lại giữa các màn hình bằng CardLayout, cũng như cách BoxLayout kết hợp với "lò xo vô hình" (Glue) để giữ nút Đăng xuất luôn bám sát lề dưới dù bạn có phóng to hay thu nhỏ cửa sổ.


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í