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
-
Khởi tạo
CardLayoutvà gán cho một Container cha (ví dụJPanel mainPanel). -
Nhét các Panel con vào
mainPanelkèm theo một cái tên định danh (String). -
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
BoxLayoutdọc để xếp các nút Menu. Sử dụngGlueđể đẩ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