所謂布局管理器,就是為容器內的組件提供若干布局策略,每個容器都擁有某種默認布局管理器,用於負責其內部組件的排列。目前開發中,常用的布局管理器有BorderLayout、FlowLayout、GridLayout、GridBagLayout、CardLayout、BoxLayout、SpringLayout、GroupLayout等:
以上布局管理器各有特色,適用於不同的場合。
布局管理器能將各種組件在頂層容器內排列的井井有條,那麼,布局管理器為什麼能夠有如此能力?它是如何工作的呢?下面將講述有關布局管理的工作原理。
在創建好頂層框架後,會調用JFrame的pack方法,用於指定頂層框架所必須的首選大小。而這個首選大小是框架的內容窗口大小與框架菜單欄的大小之和。內容窗口的布局管理器主要負責計算內容窗口的首選大小,例如要使用一個具有兩列的GridLayout來布局,那麼系統會將所有的組件大小都設置為一樣的,並且使得每個組件的高度和寬度與所有組件中高度和寬度最大的組件相同。通過這種方式計算出內容窗口的首選大小。然後,根據每個組件的大小,按照先後或在坐標位置,將之放入到布局管理器所布局的組件中去。
和 AWT相同,為了容器中組件能實現與平台無關的自動合理排列,Swing也采用了布局管理器來管理組件的排放、位置、大小等布置任務,在此基礎上將顯示風格做了改進。另外一個不同點在於,Swing雖然有頂層容器,但是不能把組件直接加到頂層容器中,Swing窗體中含有一個成為內容面板的容器(ContentPane),也可以說是中間容器。在頂層容器上放置內容面板,然後把組件加入到內容面板中,所以在Swing中,設置布局管理器是針對內容面板的,另外Swing新增加了一個BoxLayout布局管理器,顯示與AWT略有不同。
BorderLayout是一種簡單的布局策略,在使用在這個布局管理器時,應將其看作是一個組件,所以,首先應通過構造器創建布局管理器對象,再通過引用其中的方法和變量來對組件進行布局。下面將以表格形式列舉出BorderLayout布局管理器的構造器。
這個布局管理器把容器分為東、南、西、北、中5個區域,每個組件將占據某個區域。而這5個區域分別被命名為NORTH、WEST、EAST、CENTER、SOUTH,它們都被定義為靜態常量,靜態常量可以直接引用。如下表所示:
當向某個區域內添加控件時,就要將代表區域的常數作為第2個參數傳遞給add方法參數,而將需要添加到某個區域的控件作為add方法的第1個參數,如add(組件名稱,方位)。可參考下面BorderLayout實例代碼:
import javax.swing.*;
import java.awt.*;
/**
* BorderLayout
* Created by veione on 5/9/16.
*/
public class BorderLayoutCase {
private static final int WIDTH = 300;
private static final int HEIGHT = 200;
public static void main(String[] args) {
JFrame frame = new JFrame("BorderLayout");
frame.setSize(WIDTH, HEIGHT);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
Tools.centerWindow(frame);
JPanel contentPane = new JPanel();
frame.setContentPane(contentPane);
JButton btnLife = new JButton("生活");
JButton btnWork = new JButton("工作");
JButton btnSleep = new JButton("睡覺");
JButton btnShopping = new JButton("購物");
JButton btnFood = new JButton("飲食");
//創建一個布局管理器,將中間容器設置為此布局管理器
BorderLayout borderLayout = new BorderLayout();
frame.setLayout(borderLayout);
contentPane.add(btnLife, BorderLayout.NORTH);
contentPane.add(btnWork, BorderLayout.SOUTH);
contentPane.add(btnSleep, BorderLayout.EAST);
contentPane.add(btnShopping, BorderLayout.WEST);
contentPane.add(btnFood, BorderLayout.CENTER);
frame.setVisible(true);
}
}
以上代碼運行之後,如下圖所示:
這種布局管理器的策略也非常簡單,它是按照控件加入的先後順序從左到右排列,一行排滿了,再換下一行,然後繼續從左到右排列。每一行的組件都是居中排列的。另外,如果有些按鈕看不到,可以使用pack()自動調整Frame的大小,使得所有控件都顯示出來。FlowLayout布局管理器同樣是通過先創建對象、再利用其內置方法和變量來布局的組件,下表所示是其構造其說明。
FlowLayout代碼示例:
import javax.swing.*;
import java.awt.*;
/**
* Created by veione on 5/9/16.
*/
public class SpringLayoutCase {
private static final int WIDTH=300;
private static final int HEIGHT=200;
public static void main(String[] args) {
JFrame frame=new JFrame("SpringLayout");
frame.setSize(WIDTH,HEIGHT);
Tools.centerWindow(frame);
frame.setDefaultCloseOperation(Tools.EXIT_ON_CLOSE);
JPanel contentPane=new JPanel();
frame.setContentPane(contentPane);
JButton btnLife = new JButton("生活");
JButton btnWork = new JButton("工作");
JButton btnSleep = new JButton("睡覺");
JButton btnShopping = new JButton("購物");
JButton btnFood = new JButton("飲食");
//設置內容面板布局管理器為FlowLayout
contentPane.setLayout(new FlowLayout());
contentPane.add(btnLife);
contentPane.add(btnWork);
contentPane.add(btnShopping);
contentPane.add(btnSleep);
contentPane.add(btnFood);
frame.pack();
frame.setVisible(true);
}
}
以上代碼運行之後如下圖:
這種布局管理器有點像圍棋盤,它將整個布局控件劃分成若干行乘若干列的網格區域。組件就位於這些小的區域內,要想創建一個GridLayout布局管理器,就必須通過其構造器來創建GridLayout布局管理器對象。下面說明下其構造器。
下面通過實例代碼來熟悉一下GridLayout布局管理器的使用方法,其代碼如下:
import javax.swing.*;
import java.awt.*;
/**
* GridLayout
* Created by veione on 5/9/16.
*/
public class GridLayoutCase {
private static final int WIDTH=300;
private static final int HEIGHT=200;
public static void main(String[] args) {
JFrame frame=new JFrame("GridLayout");
frame.setSize(WIDTH,HEIGHT);
frame.setDefaultCloseOperation(Tools.EXIT_ON_CLOSE);
Tools.centerWindow(frame);
//內容面板
JPanel contentPane=new JPanel();
frame.setContentPane(contentPane);
JButton hk=new JButton("港幣");
JButton rmb=new JButton("人民幣");
JButton dollar=new JButton("美元");
JButton euro=new JButton("歐元");
JButton pound=new JButton("英鎊");
JButton mainBoard=new JButton("主板");
JButton memory=new JButton("內存");
JButton hardDisk=new JButton("硬盤");
JButton monitor=new JButton("顯示器");
//創建網格布局管理器對象,指定3行3列
GridLayout gridLayout=new GridLayout(3,3);
contentPane.setLayout(gridLayout);
//將控件添加到內容面板中
contentPane.add(hk);
contentPane.add(rmb);
contentPane.add(dollar);
contentPane.add(euro);
contentPane.add(pound);
contentPane.add(mainBoard);
contentPane.add(memory);
contentPane.add(hardDisk);
contentPane.add(monitor);
frame.pack();
frame.setVisible(true);
}
}
以上代碼運行結果如下:
GridBagLayout是一種很先進的、很人性化的布局管理器,通過網格的劃分,可以看到每個組件都占據一個網格,也可以一個組件占據幾個網格。與GridLayout布局管理器不同的是,GridBagLayout是按照開發人員自己的思路來排列控件位置,而GridLayout布局管理器根據系統的安排來布局。如果要采用網格組布局管理器,一般可采用下列步驟:
1.創建一個GridBagLayout對象
2.將容器設成此對象的布局管理器
3.創建約束(GridBagConstraints)對象
4.創建各個相應的組件
5.添加各個組件與約束到網格組布局管理器中網格組由多個網格組成,而且各個行或在列的長度和寬度不同。但默認情況下,單元格從左上角開始有序列的編號,從第0行、第0列開始計數。
當向網格組布局管理器中添加組件時,需要分別定義每個單元格的序列號,只要設定相應的值,那麼組件就會添加到網格組布局管理器中。涉及到組件被添加到什麼位置有4個參數,即gridX、gridY、gridwidth、gridheight。其中,gridX、gridY分別定義了添加組件時左上角的行與列的位置,而gridwidth、gridheight分別定義了組件所占用的列數和行數。
網格組布局管理器中每個區域都要設置增量字段(weightx與weighty分別代表x方向和y方向的增量)。如果想讓某個區域保持初始化大小,也就是說窗口縮放不會引起組件縮放,那就應該設置該區域的增量為0,相反如果讓組件能隨時完全填充單元格,那增量字段就應該設置為100。這個布局管理器對象中還涉及到了兩個參數,即fill和anchor。
這兩個參數都是非常重要的約束,其中當組件不能填滿單元格時,fill參數就可以發揮作用。該約束的值主要有以下幾種。
- GridBagConstraints.NONE:在每一個方向都不填充,即保持原狀。
- GridBagConstraints.HORIZONTAL:只在水平方向上填充。
- GridBagConstraints.VERTICAL:只在垂直方向上填充。
- GridBagConstraints.BOTH:在兩個方向上都填充。而anchor參數則是當一個組件大於分配給它的單元格時發揮作用,該約束就是約定如何處理該組件,它的值如下所示:
- GridBagConstraints.CENTER:居中縮小。
- GridBagConstraints.NORTH:頂部縮小。
- GridBagConstraints.NORTHEAST:左上角縮小。
- GridBagConstraints.EAST:右側縮小。
GridBagLayout布局管理器的構造器只有一種,就是不帶參數的構造器。下面通過代碼認識下該布局管理器。
import javax.swing.*;
import java.awt.*;
/**
* GridBagLayout
* Created by veione on 5/9/16.
*/
public class GridBagLayoutCase extends JPanel{
private static final int WIDTH=300;
private static final int HEIGHT=200;
JFrame loginFrame;
public void add(Component c,GridBagConstraints constraints,int x,int y,int w,int h){
constraints.gridx=x;
constraints.gridy=y;
constraints.gridwidth=w;
constraints.gridheight=h;
add(c,constraints);
}
public GridBagLayoutCase(){
//設置頂層容器
loginFrame=new JFrame("信息管理系統");
loginFrame.setDefaultCloseOperation(Tools.EXIT_ON_CLOSE);
//創建網格組布局方式對象
GridBagLayout layout=new GridBagLayout();
setLayout(layout);
loginFrame.add(this,BorderLayout.WEST);
loginFrame.setSize(WIDTH,HEIGHT);
Tools.centerWindow(loginFrame);
JButton btnOk=new JButton("確認");
JButton btnCancel=new JButton("取消");
JLabel lblTitle=new JLabel("用戶登錄");
JLabel lblName=new JLabel("用戶名");
JLabel lblPwd=new JLabel("密碼");
JTextField txtName=new JTextField(15);
JPasswordField txtPwd=new JPasswordField(15);
//創建約束對象
GridBagConstraints constraints=new GridBagConstraints();
constraints.fill=GridBagConstraints.NONE;
constraints.anchor=GridBagConstraints.EAST;
constraints.weightx=3;
constraints.weighty=4;
add(lblTitle,constraints,0,0,3,1);
add(lblName,constraints,0,1,1,1);
add(lblPwd,constraints,0,2,1,1);
add(txtName,constraints,2,1,1,1);
add(txtPwd,constraints,2,2,1,1);
add(btnOk,constraints,0,3,1,1);
add(btnCancel,constraints,2,3,1,1);
loginFrame.setResizable(false);
loginFrame.setVisible(true);
}
public static void main(String[] args) {
new GridBagLayoutCase();
}
}
以上代碼運行結果如下:
CardLayout布局管理器非常簡單,它將容器中的每一個組件當作一個卡片,一次僅有一個卡片可見,如最初顯示容器時,CardLayout對象的第一個組件可見,其它組件都是不可見的。下面將以表格形式給出CardLayout布局管理器的構造器。
在這個布局管理器中還有一些常用方法,說明如下:
下面通過代碼實例來熟悉下它的使用:
import javax.swing.*;
import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
/**
* CardLayout
* Created by veione on 5/9/16.
*/
public class CardLayoutCase extends JFrame{
//主要的JPanel,該JPanel的布局管理器將被設置成CardLayout
private JPanel pane=null;
private JPanel btnPanel=null;
private CardLayout cardLayout=null;
private JButton btnPrevious=null;
private JButton btnNext=null;
private JButton btnDot1=null;
private JButton btnDot2=null;
private JButton btnDot3=null;
private JPanel panel1,panel2,panel3;
public CardLayoutCase(){
super("CardLayout");
cardLayout=new CardLayout(5,5);
pane=new JPanel(cardLayout);
btnPrevious=new JButton("< 上一步");
btnNext=new JButton("下一步 >");
btnDot1=new JButton("1");
btnDot2=new JButton("2");
btnDot3=new JButton("3");
btnDot3.setMargin(new Insets(2,2,2,2));
btnDot2.setMargin(new Insets(2,2,2,2));
btnDot1.setMargin(new Insets(2,2,2,2));
//構造放按鈕的面板容器
btnPanel=new JPanel();
btnPanel.add(btnPrevious);
btnPanel.add(btnDot1);
btnPanel.add(btnDot2);
btnPanel.add(btnDot3);
btnPanel.add(btnNext);
//顯示的面板1-2-3
panel1=new JPanel();
panel2=new JPanel();
panel3=new JPanel();
panel1.setBackground(Color.red);
panel2.setBackground(Color.cyan);
panel3.setBackground(Color.green);
panel1.add(new JLabel("面板1"));
panel2.add(new JLabel("面板2"));
panel3.add(new JLabel("面板3"));
//將3個面板添加到上層容器中
pane.add(panel1,"panel1");
pane.add(panel2,"panel2");
pane.add(panel3,"panel3");
//給按鈕添加事件
btnPrevious.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
cardLayout.previous(pane);
}
});
btnNext.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
cardLayout.next(pane);
}
});
btnDot1.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
cardLayout.show(pane,"panel1");
}
});
btnDot2.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
cardLayout.show(pane,"panel2");
}
});
btnDot3.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
cardLayout.show(pane,"panel3");
}
});
this.getContentPane().add(pane);
this.getContentPane().add(btnPanel,BorderLayout.SOUTH);
setDefaultCloseOperation(Tools.EXIT_ON_CLOSE);
setSize(300,200);
Tools.centerWindow(this);
setVisible(true);
}
public static void main(String[] args) {
new CardLayoutCase();
}
}
箱式布局比較靈活,也比較使用。Swing提供的BOX類就是箱式布局類,它的默認布局管理器就是BoxLayout,在箱式布局管理器中包括兩種箱子:一種是水平箱,另外一種是垂直箱。
創建一個水平箱的代碼如下:Box horBox=Box.createHorizontalBox()
創建一個垂直箱的代碼如下:Box verBox=Box.createVerticalBox()
創建好箱子後,就可以像添加其它組件一樣添加下面的控件,代碼如下:horBox.add(okBtn);
verBox.add(cancelBtn);
兩種箱子的區別在於組件的排列順序,水平箱是按照從左到右的順序排列,而垂直箱按照從上到下的順序排列。對於箱式布局管理器而言,最關鍵的就是每個組件的3個尺寸。
下面是水平箱式布局管理器中組件排列的幾個重點:
如果首選寬度總和小於箱的寬度,那麼所有的組件都會相應的延伸,直到適應這個箱子的寬度。組件從左到右排列,並且相鄰兩個組件之間沒有多余的空格。
箱式布局組件之間沒有空隙,那麼就要通過一個稱為填充物的組件來提供空隙。箱式布局管理器提供了3種填充物:支柱、固定區、彈簧。下面將通過代碼來說明給布局管理器:
import javax.swing.*;
import java.awt.*;
/**
* BoxLayout
* Created by veione on 5/9/16.
*/
public class BoxLayoutCase extends JFrame{
private static final int WIDTH=300;
private static final int HEIGHT=200;
public BoxLayoutCase(){
setTitle("BoxLayout");
setSize(WIDTH,HEIGHT);
Container con=getContentPane();
JLabel label=new JLabel("姓名:");
JTextField txtField=new JTextField(10);
txtField.setMaximumSize(txtField.getPreferredSize());
//創建一個水平箱子
Box horBox=Box.createHorizontalBox();
horBox.add(label);
//在水平箱子上添加一個標簽組件,並且創建一個不可見的20個單位的組件
//在這之後再添加一個文本框組件
horBox.add(Box.createHorizontalStrut(20));
horBox.add(txtField);
JLabel labelPwd=new JLabel("密碼:");
JPasswordField txtPwd=new JPasswordField(10);
txtPwd.setMaximumSize(txtPwd.getPreferredSize());
//創建一個水平箱子
Box pwdHorBox=Box.createHorizontalBox();
pwdHorBox.add(labelPwd);
pwdHorBox.add(Box.createHorizontalStrut(20));
pwdHorBox.add(txtPwd);
JButton btnOk=new JButton("確定");
JButton btnCancel=new JButton("取消");
//創建一個水平箱子
Box btnHorBox=Box.createHorizontalBox();
btnHorBox.add(btnOk);
btnHorBox.add(Box.createHorizontalStrut(20));
btnHorBox.add(btnCancel);
//創建一個垂直箱子將水平箱子放入到垂直箱子種
Box vBox=Box.createVerticalBox();
vBox.add(horBox);;
vBox.add(pwdHorBox);
vBox.add(btnHorBox);
con.add(vBox,BorderLayout.CENTER);
Tools.centerWindow(this);
setVisible(true);
}
public static void main(String[] args) {
new BoxLayoutCase();
}
}
以上代碼運行結果為:
SpringLayout布局管理器是通過定義組件的邊沿距離來實現布局的。邊界之間的距離是使用Spring對象來表示的。每一個Spring對象具有4個屬性值,包括minimum、maximum、preferred、value,其中value表示的是真實的值。
在在這個管理器中,涉及到如下幾個常量:
void putConstraint(Stirng e1,int pad,String e2,Component c2);
import javax.swing.*;
/**
* SpringLayout
* Created by veione on 5/9/16.
*/
public class SpringLayoutDemo {
private static final int WIDTH=300;
private static final int HEIGHT=200;
public static void main(String[] args) {
JFrame frame=new JFrame("SpringLayout");
frame.setVisible(true);
frame.setSize(WIDTH,HEIGHT);
Tools.centerWindow(frame);
JPanel contentPane=new JPanel();
frame.setContentPane(contentPane);
JButton btnLoad=new JButton("加載");
JButton btnTest=new JButton("測試");
JLabel label=new JLabel("測試程序");
contentPane.add(label);
contentPane.add(btnLoad);
contentPane.add(btnTest);
//創建一個SpringLayout布局管理器,並且將之作為中間容器的布局方式
SpringLayout springLayout=new SpringLayout();
contentPane.setLayout(springLayout);
//針對每個組件設置其與邊界的距離
springLayout.putConstraint(SpringLayout.NORTH,label,5,SpringLayout.NORTH,contentPane);
springLayout.putConstraint(SpringLayout.WEST,label,85,SpringLayout.WEST,contentPane);
springLayout.putConstraint(SpringLayout.EAST,label,5,SpringLayout.EAST,contentPane);
springLayout.putConstraint(SpringLayout.NORTH,btnLoad,55,SpringLayout.NORTH,contentPane);
springLayout.putConstraint(SpringLayout.WEST,btnLoad,5,SpringLayout.WEST,contentPane);
springLayout.putConstraint(SpringLayout.EAST,btnLoad,25,SpringLayout.EAST,contentPane);
springLayout.putConstraint(SpringLayout.NORTH,btnTest,105,SpringLayout.NORTH,contentPane);
springLayout.putConstraint(SpringLayout.WEST,btnTest,5,SpringLayout.WEST,contentPane);
springLayout.putConstraint(SpringLayout.EAST,btnTest,25,SpringLayout.EAST,contentPane);
frame.setVisible(true);
}
}
運行結果如下:
從GroupLayout的單詞意思來看,它是以Group(組)為單位來管理布局,也就是把多個組件(如:JLabel、JButton)按區域劃分到不同的Group(組),再根據各個Group(組)相對於水平軸(Horizontal)和垂直軸(Vertical)的排列方式來管理。
下面通過代碼來熟悉下它的使用:
import javax.swing.*;
import java.awt.*;
/**
* GroupLayout
* Created by veione on 5/9/16.
*/
public class GroupLayoutCase extends JFrame{
public GroupLayoutCase(){
//創建一個中間容器,並且創建一個GroupLayout布局管理器對象
Container c=getContentPane();
GroupLayout layout=new GroupLayout(c);
//創建兩個普通按鈕組件,文本框組件
JButton btn1=new JButton("按鈕1");
JButton btn2=new JButton("按鈕2");
JTextField text=new JTextField("吻鳄不能");
//創建一個hsg組,將兩個按鈕以一個一個的添加到組裡面
GroupLayout.SequentialGroup hsg=layout.createSequentialGroup();
hsg.addComponent(btn1);
hsg.addComponent(btn2);
GroupLayout.ParallelGroup hpg=layout.createParallelGroup(GroupLayout.Alignment.CENTER);
//創建一個hpg組,將文本框組件和上面的那個組添加到其中,並且將之劇中排列
hpg.addComponent(text).addGroup(hsg);
layout.setHorizontalGroup(hpg);
GroupLayout.ParallelGroup vpg=layout.createParallelGroup();
vpg.addComponent(btn1);
vpg.addComponent(btn2);
GroupLayout.SequentialGroup vsg=layout.createSequentialGroup();
vsg.addComponent(text).addGroup(vpg);
layout.setVerticalGroup(vsg);
setLayout(layout);
setDefaultCloseOperation(Tools.EXIT_ON_CLOSE);
pack();
setVisible(true);
}
public static void main(String[] args) {
new GroupLayoutCase();
}
}
運行結果如下:
好了,Java布局管理器到此為止!