GIÁO TRÌNH

Core Java

Science and Technology

Quản lý cách trình bày (Layout Manager)

Tác giả: Huỳnh Công Pháp

Layout manager điều khiển cách trình bày vật lý của các phần tử GUI như là button, textbox, option button v.v… Một layout manager tự động bố trí các thành phần này trong container.

Các kiểu trình bày khác nhau:

  • Flow layout
  • Border layout
  • Card layout
  • Grid layout
  • GridBag Layout

Tất cả các thành phần mà chúng ta vừa tạo sử dụng layout manager mặc định. Cho ví dụ, ‘FlowLayout’ là cách trình bày mặc định của một applet. Layout manager này sẽ tự động xắp xếp các thành phần. Tất cả các thành phần được đặt trong một container, và được xắp xếp nhờ layout manager tương ứng. Layout manager được thiết lập bằng phương thức ‘setLayout()’.

Bây giờ chúng ta sẽ tìm hiểu chi tiết các cách trình bày và cách bố trí các thành phần của ta vào những vị trí mong muốn.

FlowLayout manager

FlowLayout’ là layout manager mặc định cho AppletPanel. Các thành phần được xắp xếp từ góc trái trên đến góc phải dưới của màn hình. Khi một số thành phần được tạo, chúng được xắp xếp theo hàng, từ trái sang phải. Các constructor của FlowLayout:

FlowLayout mylayout = new FlowLayout() // constructor //constructor with alignment specified FlowLayout exLayout=new FlowLayout(FlowLayout.RIGHT); setLayout(exLayout); //setting the layout to Flowlayout

Các điều khiển có thể được canh về bên trái, bên phải hay ở giữa. Để canh các điều khiển về bên phải, bạn sử dụng cú pháp sau:

setLayout(new FlowLayout(FlowLayout.RIGHT));
Chương trình minh họa về Flowlayout Manager
import java.awt.*; class Fltest extends Frame { Button b1=new Button("Center Aligned Button 1"); Button b2=new Button("Center Aligned Button 2"); Button b3=new Button("Center Aligned Button 3"); public Fltest(String title) { super(title); setLayout(new FlowLayout(FlowLayout.CENTER)); add(b1); add(b2); add(b3); } public static void main(String args[]) { Fltest t=new Fltest("Flow Layout"); t.setSize(300,200); t.show(); } }

Kết xuất của chương trình chỉ ra ở [link].

Flowlayout

BorderLayout Manager

BorderLayout’ là layout manager mặc định cho ‘Window’, ‘Frame’ và ‘Dialog’. Layout này xắp xếp tối đa 5 thành phần trong một container. Những thành phần này có thể được đặt ở các hướng ‘North’, ‘South’, ‘East’, ‘West’ và ‘Center’ của container.

  • NORTH – Đặt ở đỉnh của container.
  • EAST – Đặt phía bên phải của container.
  • SOUTH – Đặt ở phía dưới của container.
  • WEST – Đặt phía bên trái của container.
  • CENTER – Đặt ở giữa của container.

Để thêm một thành phần vào vùng ‘North’, bạn sử dụng cú pháp sau:

Button b1=new Button("North Button"); // khai báo thành phần setLayout(new BorderLayout()); // thiết lập layout add(b1,BorderLayout.NORTH); // thêm thành phần vào layout

Các thành phần vẫn giữ nguyên vị trí tương đối của chúng kể cả khi container bị thay đổi kích thước. Các thành phần được đặt trong vùng ‘North’, ‘South’ được dàn nằm ngang trong khi đó các thành phần đặt trong vùng ‘East’ và ‘West’ lại được dàn thẳng đứng. Các thành phần được đặt trong vùng ‘center’ sẽ được dàn đều vào những khu vực nằm giữa của container.

add(b2,BorderLayout.CENTER); // thêm thành phần vào vùng ‘center’

Khi tất cả các thành phần được đặt vào các vùng tương ứng, lúc đó Frame sẽ giống như sau:

BorderLayout

BorderLayout có thể chứa nhiều hơn 5 thành phần. Để thực hiện điều này, chúng ta có thể sử dụng các Panel với các layout khác nhau để chứa các thành phần, và sau đó đặt các panel này vào trong BorderLayout.

CardLayout Manager

CardLayout có thể lưu trữ một ngăn xếp (stack) các giao diện. Mỗi giao diện giống như một bảng (card). Bảng thường là đối tượng Panel. Một thành phần độc lập như button sẽ điều khiển cách trình bày các bảng ở lớp trên cùng.

Đầu tiên, chúng ta bố trí tập hợp các thành phần được yêu cầu trên các panel tương ứng. Mỗi panel sẽ được bố trí vào các layout khác nhau. Ví dụ:

panelTwo.setLayout(new GridLayout(2,1));

Panel chính sẽ chứa những panel này. Chúng ta thiết lập layout của panel chính là Cardlayout như sau:

CardLayout card=new CardLayout(); panelMain.setLayout(card);

Bước kế tiếp là thêm các panel khác vào panel chính:

panelMain.add("Red Panel", panelOne); panelMain.add("Blue Panel", panelTwo);

Phương thức ‘add()’ sử dụng hai tham số. Tham số đầu tiên là một String làm nhãn của panel và tham số thứ hai là tên đối tượng Panel.

Chương trình minh họa Cardlayout
import java.awt.*; import java.applet.*; /*<applet code="CardLayoutDemo.class" width="300" height="100"></applet>*/ public class CardLayoutDemo extends Applet { Button back,next; Label lbl1,lbl2,lbl3,lbl4; TextField other1; Panel p1,first,second,third,fourth; CardLayout c1; public void init() { back=new Button("Back"); next=new Button("Next"); add(back); add(next); c1=new CardLayout(); p1=new Panel(); p1.setLayout(c1);// Set panel layout to CardLayout lbl1=new Label("First"); lbl2=new Label("Second"); lbl3=new Label("Third"); lbl4=new Label("Fourth"); //First panel first=new Panel(); first.add(lbl1); //Second panel second=new Panel(); second.add(lbl2); //Third panel third=new Panel(); third.add(lbl3); //Fourth panel fourth=new Panel(); fourth.add(lbl4); //Add panels to the card deck panel p1.add("1",first); p1.add("2",second); p1.add("3",third); p1.add("4",fourth); add(p1); } }

Kết xuất của chương trình như sau:

CardLayout

Trong hình bên trên, các panel được thêm vào panel chính như là các thẻ riêng biệt. Vì thế chỉ có thẻ đầu tiên mới được thấy trên màn hình. Nhưng người dùng có thể điều hướng sang các panel khác sử dụng các phương thức của CardLayout.

GridLayout Manager

‘GridLayout’ trợ giúp việc chia container vào trong ô lưới. Các thành phần được đặt trong các ô giao của dòng và cột. Mỗi lưới nên chứa ít nhất một thành phần. Một lưới được sử dụng khi tất cả các thành phần có cùng kích thước.

GridLayout được tạo như sau:

Gridlayout g1=new GridLayout(4,3);

4 là số dòng và 3 là số cột.

Chương trình minh họa cách trình bày lưới
import java.awt.*; class Gltest extends Frame { Button btn[]; String str[]={"1", "2", "3", "4", "5", "6", "7", "8", "9"}; public Gltest(String title) { super(title); setLayout(new GridLayout(3,3)); btn=new Button[str.length]; for (int i=0; i<str.length;i++) { btn[i]=new Button(str[i]); add(btn[i]); } } public static void main(String args[]) { Gltest t=new Gltest("Grid Layout"); t.setSize(300,200); t.show(); } }

Kết xuất chương trình như sau:

GridLayout

GridBagLayout Manager

‘GridBagLayout’ là cách trình bày hiệu quả và phức tạp hơn bất cứ cách trình bày nào khác. Layout này đặt các thành phần vào vị trí chính xác. Với layout này, các thành phần không cần có cùng kích thước. Nó tương tự như GridLayout manager, khi các thành phần được xắp xếp trong lưới theo dòng và cột. Tuy nhiên, thứ tự đặt các thành phần không theo nguyên tắc từ trái sang phải và từ trên xuống dưới.

GridBagLayout gb=new GridBagLayout() ContainerName.setLayout(gb);

Để sử dụng layout này, bạn cần cung cấp thông tin về kích thước và vị trí của mỗi thành phần. Lớp ‘GridBagLayoutConstraints’ chứa tất cả các thông tin mà lớp GridLayout cần để bố trí và định kích thước mỗi thành phần. Bảng sau liệt kê danh sách các biến thành viên của lớp GridBagConstraints:

Các biến thành viên của lớp GridBagConstraints
Các biến thành viên Mục đích
weightx, weighty Chỉ ra sự phân phối của khoảng trống trong GridBagLayout. Giá trị mặc định cho các biến này là 0.
gridwidth, gridheight Chỉ ra số lượng các ô (cell) chiều ngang và chiều dọc trong vùng hiển thị của một thành phần.
ipadx, ipady Chỉ ra lượng làm thay đổi chiều cao và chiều rộng tối thiểu của thành phần. Nó sẽ thêm 2*ipadx vào chiều rộng tối thiểu và 2*ipady vào chiều cao tối thiểu của thành phần. Giá trị mặc định cho cả hai là 0.
anchor Chỉ ra cách xắp xếp các thành phần trong cell. Mặc định sẽ đặt vào giữa cell. Các thành viên dữ liệu tĩnh (static) sau đây có thể được sử dụng:
  • GridBagConstraints.NORTH
  • GridBagConstraints.EAST
  • GridBagConstraints.WEST
  • GridBagConstraints.SOUTH
  • GridBagConstraints.NORTHEAST
  • GridBagConstraints.SOUTHEAST
gridx, gridy Chỉ ra vị trí cell sẽ đặt thành phần. Khi thiết lập giá trị của gridx là ‘GridbagConstraints.RELATIVE’ thì thành phần được thêm sẽ nằm ở vị trí bên phải của thành phần cuối cùng.
fill Chỉ ra cách mà một thành phần được bố trí vào cell thế nào nếu như cell lớn hơn thành phần. Mặc định là kích thước thành phần không thay đổi.

Bảng sau đây cung cấp một danh sách các biến dữ liệu tĩnh là các giá trị cho biến fill:

Các biến thành viên dữ liệu tĩnh của biến fill
Giá trị Mô tả
GridBagConstraints.NONE Mặc định, không làm thay đổi kích thước của thành phần.
GridBagConstraints.HORIZONTAL Tăng chiều rộng của thành phần theo chiều ngang (HORIZONTAL) để làm cho thành phần khớp với chiều ngang.
GridBagConstraints.VERTICAL Tăng chiều cao của thành phần theo chiều đứng (VERTICAL) để làm cho thành phần khớp với chiều dọc.
GridBagConstraints.BOTH Tăng chiều rộng, chiều cao của thành phần theo cả chiều ngang và chiều dọc.
insets Xác định khoảng cách top, buttom, left và right giữa các thành phần. Mặc định là 0.

Sử dụng phương thức ‘setConstraints()’ để thiết lập các hằng số cho mỗi thành phần. Cho ví dụ:

gblay.setConstraints(lb1, gbc);

‘gblay’ là đối tượng của lớp GridBagLayout, lbl là thành phần ‘Label’ và ‘gbc’ là đối tượng của lớp GridBagConstraints.

Chương trình minh họa của GridBaglayout và GridBagConstraints
import java.awt.*; class Gbltest extends Frame { TextArea ta; TextField tf; Button b1,b2; CheckboxGroup cbg; Checkbox cb1,cb2,cb3,cb4; GridBagLayout gb; GridBagConstraints gbc; public GBltest(String title) { super(title); gb=new GridBagLayout(); setLayout(gb); gbc=new GridBagConstraints(); ta=new TextArea("Textarea",5,10); tf=new TextField("enter your name"); b1=new Button("TextArea"); b2=new Button("TextField"); cbg=new CheckboxGroup(); cb1=new Checkbox("Bold", cbg,false); cb2=new Checkbox("Italic", cbg,false); cb3=new Checkbox("Plain", cbg,false); cb4=new Checkbox("Bold/Italic", cbg,true); gbc.fill=GridBagConstraints.BOTH; addComponent(ta,0,0,4,1); gbc.fill=GridBagConstraints.HORIZONTAL; addComponent(b1,0,1,1,1); gbc.fill=GridBagConstraints.HORIZONTAL; addComponent(b2,0,2,1,1); gbc.fill=GridBagConstraints.HORIZONTAL; addComponent(cb1,2,1,1,1); gbc.fill=GridBagConstraints.HORIZONTAL; addComponent(cb2,2,2,1,1); gbc.fill=GridBagConstraints.HORIZONTAL; addComponent(cb3,3,1,1,1); gbc.fill=GridBagConstraints.HORIZONTAL; addComponent(cb4,3,2,1,1); gbc.fill=GridBagConstraints.HORIZONTAL; addComponent(tf,4,0,1,3); } public void addComponent(Component c, int row, int col, int nrow, int ncol) { gbc.gridx=col; gbc.gridy=row; gbc.gridwidth=ncol; gbc.gridheight=ncol; gb.setConstraints(c,gbc); add(c); } public static void main(String args[]) { Gbltest t=new Gbltest("GridBag Layout"); t.setSize(300,200); t.show(); } }

Khi một container bị thay đổi kích thước và khi khoảng trắng phụ tồn tại, các thành phần có chiều rộng lớn hơn sẽ chiếm giữ nhiều khoảng trống hơn là các thành phần có giá trị về chiều rộng nhỏ hơn.

Kết xuất của chương trình được chỉ ra ở [link]

GridBagLayout

Giải thích đoạn mã trên:

gbc.fill=GridBagConstraints.BOTH;

Thành viên fill của lớp GridBagConstraints chỉ ra thành phần có thể được mở rộng theo hướng nằm ngang và thẳng đứng. Cú pháp sau mô tả thành phần chỉ được mở rộng theo hướng nằm ngang:

gbc.fill=GridBagConstraints.HORIZNTAL;

Cú pháp sau sẽ thêm vào thành phần TextArea với số dòng và số cột cần chiếm:

addComponent(ta,0,2,4,1);

0 – Khởi đầu từ dòng thứ 0

2 – Khởi đầu từ dòng thứ 2

4 – ta chiếm giữ 4 dòng

1 – ta chiếm 1 cột

Sử dụng cú pháp sau để bố trí các thành phần vào trong dòng và cột nào đó:

gbc.gridx=col; gbc.gridy=row;

Ở đây (gridx,gridy) là cột và dòng nơi mà thành phần có thể được đặt vào.

Sử dụng cú pháp sau để chỉ ra số lượng các cột và dòng mà các thành phần có thể chiếm giữ:

gbc.gridwitdh=ncol; gbc.gridheight=nrow;

Ở đây, gridwidth xác định số lượng các cột mà một thành phần chiếm giữ và gridheight xác định số lượng các dòng mà một thành phần chiếm giữ.

Khi một container bị thay đổi kích thước và khi khoảng trắng phụ tồn tại, các thành phần có chiều rộng lớn hơn sẽ chiếm giữ nhiều khoảng trống hơn là các thành phần có giá trị về chiều rộng nhỏ hơn.