Bài 41: Layout trong Java Swing - Lập trình Java cơ bản

Đăng bởi: Admin | Lượt xem: 6570 | Chuyên mục: Java


Layout có tác dụng tự động bố trí các component trên container, bạn tưởng tượng layout giống như một căn nhà có nhiều phòng và các phòng này có thể tự thay đổi kích thước cũng như vị trí theo một quy luật nào đó và theo đó mà cách vật dụng trong phòng cũng tự thay đổi theo. Đối với người mới bắt đầu lập trình GUI thì layout là một khái niệm khá khó hiểu vì nó không có hình ảnh trực quan như text hay button.
Cũng có những trường hợp chúng ta không cần dùng đến layout. Tuy nhiên nên dùng thì vẫn tốt hơn.

1. FlowLayout

Đây là loại layout đơn giản nhất, layout này thường được dùng kết hợp với các layout khác. Layout này quy định kích thước của các component con là vừa đủ với nội dung hiển thị của component.
Mặc định các component sẽ được sắp xếp trên một hàng từ trái sang phải, nếu không vừa đủ một hàng thì chúng sẽ xuống hàng. Các component sẽ cách nhau 5 pixel và cách viền cửa sổ 5 pixel. Tuy nhiên chúng ta có thể thay đổi các thuộc tính này.
FlowLayout()
FlowLayout(int align)
FlowLayout(int align, int hgap, int vgap)
Ở trên là 3 kiểu khởi tạo một FlowLayout, align quy định sắp xếp từ trái sang phải hay ngược lại, hgap là khoảng cách giữa các component theo chiều ngang, vgap là khảng cách giữa các component theo chiều dọc.
Ví dụ:
import java.awt.Dimension;
 
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.JTextArea;
import javax.swing.JTree;
import javax.swing.SwingUtilities;
 
 
public class FlowLayoutExample extends JFrame {
 
 
    public FlowLayoutExample() {
 
        initUI();
    }
 
    public final void initUI() {
 
        JPanel panel = new JPanel();
 
        JTextArea area = new JTextArea("text area");
        area.setPreferredSize(new Dimension(100, 100));
 
        JButton button = new JButton("button");
        panel.add(button);
 
        JTree tree = new JTree();
        panel.add(tree);
 
        panel.add(area);
 
        add(panel);
 
        pack();
 
        setTitle("Layout Example");
        setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        setLocationRelativeTo(null);
    }
 
    public static void main(String[] args) {
 
        SwingUtilities.invokeLater(new Runnable() {
 
            public void run() {
 
                FlowLayoutExample ex = new FlowLayoutExample();
                ex.setVisible(true);
            }
        });
    }
}
Kết quả thu được:

2. GridLayout

Layout này sắp xếp các component theo dạng bảng. Các component sẽ có kích thước bằng nhau.
Ví dụ:
import java.awt.GridLayout;
 
import javax.swing.BorderFactory;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.SwingUtilities;
 
 
public class GridLayoutExample extends JFrame {
 
    public GridLayoutExample() {
 
        initUI();
    }
 
    public final void initUI() {
 
        JPanel panel = new JPanel();
 
        panel.setBorder(BorderFactory.createEmptyBorder(5, 5, 5, 5));
        panel.setLayout(new GridLayout(5, 4, 5, 5));
 
        String[] buttons = {
            "Cls", "Bck", "", "Close", 
            "7", "8", "9", "/", 
            "4", "5", "6", "*", 
            "1", "2", "3", "-", 
            "0", ".", "=", "+"
        };
 
        for (int i = 0; i < buttons.length; i++) {
 
            if (i == 2)
                panel.add(new JLabel(buttons[i]));
            else
                panel.add(new JButton(buttons[i]));
        }
 
        add(panel);
 
        setTitle("Layout Example");
        setSize(350, 300);
        setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        setLocationRelativeTo(null);
    }
 
    public static void main(String[] args) {
 
        SwingUtilities.invokeLater(new Runnable() {
 
            public void run() {
 
                GridLayoutExample ex = new GridLayoutExample();
                ex.setVisible(true);
            }
        });
    }
}
Chúng ta sẽ tạo giao diện máy tính bỏ túi.
1panel.setLayout(newGridLayout(5, 4, 5, 5));
Trong phương thức khởi tạo GridLayout, 2 tham số đầu là số hàng và số cột, hai tham số cuối là khoảng cách giữa các component theo chiều ngang và chiều dọc.
Kết quả thu được:

3. BorderLayout

BorderLayout sắp xếp các component theo vùng, ở đây có 5 vùng là Đông (EAST), Tây (WEST), Nam (SOUTH), Bắc (NORTH), và Chính giữa (CENTER). Nhưng mỗi vùng chỉ được chứa một component, do đó khi muốn đưa nhiều component vào một vùng thì chúng ta đặt một layout khác vào vùng đó rồi đặt các component vào layout mới đó. Khác với các layout khác, kích thước của các component trong mỗi vùng là do chúng ta thiết lập chứ không phải do layout tự co dãn, ngoại trừ vùng CENTER sẽ có kích thước thay đổi tùy thuộc vào 4 vùng còn lại.
Ví dụ:
import java.awt.BorderLayout;
import java.awt.Dimension;
import java.awt.Insets;
 
import javax.swing.ImageIcon;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JMenu;
import javax.swing.JMenuBar;
import javax.swing.JTextArea;
import javax.swing.JToolBar;
import javax.swing.SwingUtilities;
import javax.swing.border.EmptyBorder;
import javax.swing.border.LineBorder;
 
 
public class BorderLayoutExample extends JFrame {
 
 
    public BorderLayoutExample() {
 
        initUI();
    }
 
    public final void initUI() {
 
        // Create menu bar
        JMenuBar menubar = new JMenuBar();
        JMenu file = new JMenu("File");
  
        menubar.add(file);
        setJMenuBar(menubar);
  
        // Create horizontal toolbar (NORTH)
        JToolBar horizontalToolbar = new JToolBar();
        horizontalToolbar.setFloatable(false);
  
        ImageIcon exitIcon = new ImageIcon("F:/exit.png");
        JButton exitButton = new JButton(exitIcon);
        exitButton.setBorder(new EmptyBorder(0, 0, 0, 0));
        horizontalToolbar.add(exitButton);
  
        add(horizontalToolbar, BorderLayout.NORTH);
  
        // Create vertical toolbar (WEST)
        JToolBar verticalToolbar = new JToolBar(JToolBar.VERTICAL);
        verticalToolbar.setFloatable(false);
        verticalToolbar.setMargin(new Insets(10, 5, 5, 5));
  
        ImageIcon driveIcon = new ImageIcon("F:/drive.png");
        ImageIcon computerIcon = new ImageIcon("F:/computer.png");
        ImageIcon printerIcon = new ImageIcon("F:/printer.png");
  
        JButton driveButton = new JButton(driveIcon);
        driveButton.setBorder(new EmptyBorder(3, 0, 3, 0));
  
        JButton computerButton = new JButton(computerIcon);
        computerButton.setBorder(new EmptyBorder(3, 0, 3, 0));
  
        JButton printerButton = new JButton(printerIcon);
        printerButton.setBorder(new EmptyBorder(3, 0, 3, 0));
  
        verticalToolbar.add(driveButton);
        verticalToolbar.add(computerButton);
        verticalToolbar.add(printerButton);
  
        add(verticalToolbar, BorderLayout.WEST);
  
        // Craete Text area (CENTER)
        add(new JTextArea(), BorderLayout.CENTER);
  
        // Create Status bar (SOUTH)
        JLabel statusbar = new JLabel("Statusbar");
        statusbar.setPreferredSize(new Dimension(-1, 22));
        statusbar.setBorder(LineBorder.createGrayLineBorder());
        add(statusbar, BorderLayout.SOUTH);
   
        setSize(350, 300);
        setTitle("Layout Example");
        setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        setLocationRelativeTo(null);
    }
 
    public static void main(String[] args) {
 
        SwingUtilities.invokeLater(new Runnable() {
 
            public void run() {
                BorderLayoutExample ex = new BorderLayoutExample();
                ex.setVisible(true);
            }
        });
    }
}
Trong ví dụ này chúng ta sẽ tạo một giao diện giống như các ứng dụng thường thấy bao gồm 1 thanh menu, 1 toolbar nằm ngang (NORTH), 1 toolbar nằm dọc (WEST), 1 text area (CENTER), 1 status bar (SOUTH).
Mặc định JFrame dùng sẵn BorderLayout nên chúng ta không cần phải thiết lập lại.

4. BoxLayout

BoxLayout cho phép chúng ta tạo các giao diện phức tạp. Layout này sắp xếp các component theo chiều ngang hoặc chiều dọc, tức là giống với FlowLayout, chỉ khác ở chỗ là BoxLayout cho phép các component có thể tự thay đổi kích thước dựa vào kích thước cửa sổ chính. Ngoài ra bạn còn có thể lồng một BoxLayout vào một BoxLayout khác.
BoxLayout thường đi cùng với một lớp khác nữa là lớp Box, lớp này có tác dụng tạo các khoảng trống để “đẩy” các component về các vị trí khác nhau. Các loại khoảng trống mà Box có thể tạo ra là Glue, Strut và RigidArea. Mình sẽ giải thích ngay bên dưới.
Trong ví dụ này chúng ta sẽ tạo 2 button nằm ở góc dưới bên phải cửa sổ.
import java.awt.Dimension;
 
import javax.swing.Box;
import javax.swing.BoxLayout;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.SwingUtilities;
 
 
public class TwoButtonsExample extends JFrame {
 
    public TwoButtonsExample() {
 
        initUI();
    }
 
    public final void initUI() {
 
        JPanel basic = new JPanel();
        basic.setLayout(new BoxLayout(basic, BoxLayout.Y_AXIS));
        add(basic);
 
        basic.add(Box.createVerticalGlue());
 
        JPanel bottom = new JPanel();
        bottom.setAlignmentX(Component.RIGHT_ALIGNMENT);
        bottom.setLayout(new BoxLayout(bottom, BoxLayout.X_AXIS));
 
        JButton ok = new JButton("OK");
        JButton close = new JButton("Close");
 
        bottom.add(ok);
        bottom.add(Box.createRigidArea(new Dimension(5, 0)));
        bottom.add(close);
        bottom.add(Box.createRigidArea(new Dimension(15, 0)));
 
        basic.add(bottom);
        basic.add(Box.createRigidArea(new Dimension(0, 15)));
 
        setTitle("Layout Example");
        setSize(300, 150);
        setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        setLocationRelativeTo(null);
    }
 
    public static void main(String[] args) {
 
        SwingUtilities.invokeLater(new Runnable() {
 
            public void run() {
                TwoButtonsExample ex = new TwoButtonsExample();
                ex.setVisible(true);
            }
        });
    }
}
Kết quả thu được sẽ giống với minh họa sau:
Chúng ta tạo 2 panel, một panel chính sắp xếp các component theo chiều dọc, một panel thứ 2 sắp xếp các component theo chiều ngang, panel thứ 2 sẽ chứa 2 button căn lề phải. Để panel thứ 2 có thể nằm phía dưới cùng của cửa sổ (hay phía dưới cùng của panel chính) thì chúng ta dùng đến Glue. 
1basic.setLayout(newBoxLayout(basic, BoxLayout.Y_AXIS));
Đầu tiên chúng ta tạo panel chính với BoxLayout theo chiều dọc.
1basic.add(Box.createVerticalGlue());
Chúng ta tạo khoảng trống glue bằng phương thức createVerticalGlue(). Cơ chế hoạt động ở đây rất đơn giản. Ví dụ bạn đặt một button, sau đó gọi phương thức tạo glue, thì một vùng trống sẽ được thêm vào phía sau button (ở dưới button hoặc bên phải button tùy vào layout ngang hay dọc).
123JPanel bottom = newJPanel();
bottom.setAlignmentX(Component.RIGHT_ALIGNMENT);
bottom.setLayout(newBoxLayout(bottom, BoxLayout.X_AXIS));
Tiếp theo chúng ta tạo panel thứ hai và thiết lập cho các component con trượt qua lề bên phải bằng phương thức setAlignmentX(), panel này dùng BoxLayout theo chiều ngang.
1bottom.add(Box.createRigidArea(newDimension(5, 0)));
Chúng ta thêm một khoảng trống nhỏ giữa 2 button. Nhưng ở đây chúng ta không dùng glue và dùng rigid. Sự khác nhau của glue với rigid là kích thước của glue tự động thay đổi tùy theo các component, còn kích thước của rigid là do chúng ta quy định.
1basic.add(bottom);
Sau khi đã thiết kế giao diện cho panel thứ hai thì chúng ta đặt panel đó vào panel chính.
1basic.add(Box.createRigidArea(newDimension(0, 15)));
Đồng thời chúng ta cũng tạo một khoảng trống rigid giữa panel thứ 2 với cạnh đáy của cửa sổ.
Kết quả thu được:
Như vậy, thông qua bài học này, mình đã giới thiệu đến các bạn những layout cơ bản trong Java Swing. Cảm ơn các bạn đã đọc.
Bài tiếp theo: Event trong Java Swing >>
vncoder logo

Theo dõi VnCoder trên Facebook, để cập nhật những bài viết, tin tức và khoá học mới nhất!