C語言中文網 目錄
首頁 > Java Swing 閱讀:3,306

Java Swing布局管理器(詳解版)

在使用 Swing 向容器添加組件時,需要考慮組件的位置和大小。如果不使用布局管理器,則需要先在紙上畫好各個組件的位置并計算組件間的距離,再向容器中添加。這樣雖然能夠靈活控制組件的位置,實現卻非常麻煩。

為了加快開發速度,Java 提供了一些布局管理器,它們可以將組件進行統一管理,這樣開發人員就不需要考慮組件是否會重疊等問題。本節介紹 Swing 提供的 6 種布局類型,所有布局都實現 LayoutManager 接口。

邊框布局管理器

BorderLayout(邊框布局管理器)是 Window、JFrame 和 JDialog 的默認布局管理器。邊框布局管理器將窗口分為 5 個區域:North、South、East、West 和 Center。其中,North 表示北,將占據面板的上方;Soufe 表示南,將占據面板的下方;East表示東,將占據面板的右側;West 表示西,將占據面板的左側;中間區域 Center 是在東、南、西、北都填滿后剩下的區域,如圖 1 所示。

框布局管理器區域劃分示意圖
圖1 邊框布局管理器區域劃分示意圖

提示:邊框布局管理器并不要求所有區域都必須有組件,如果四周的區域(North、South、East 和 West 區域)沒有組件,則由 Center 區域去補充。如果單個區域中添加的不只一個組件,那么后來添加的組件將覆蓋原來的組件,所以,區域中只顯示最后添加的一個組件。

BorderLayout 布局管理器的構造方法如下所示。
  • BorderLayout():創建一個 Border 布局,組件之間沒有間隙。
  • BorderLayout(int hgap,int vgap):創建一個 Border 布局,其中 hgap 表示組件之間的橫向間隔;vgap 表示組件之間的縱向間隔,單位是像素。

例 1

使用 BorderLayout 將窗口分割為 5 個區域,并在每個區域添加一個標簽按鈕。實現代碼如下:
package ch17;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import java.awt.*;
public class BorderLayoutDemo
{
    public static void main(String[] agrs)
    {
        JFrame frame=new JFrame("Java第三個GUI程序");    //創建Frame窗口
        frame.setSize(400,200);
        frame.setLayout(new BorderLayout());    //為Frame窗口設置布局為BorderLayout
        JButton button1=new JButton ("上");
        JButton button2=new JButton("左");
        JButton button3=new JButton("中");
        JButton button4=new JButton("右");
        JButton button5=new JButton("下");
        frame.add(button1,BorderLayout.NORTH);
        frame.add(button2,BorderLayout.WEST);
        frame.add(button3,BorderLayout.CENTER);
        frame.add(button4,BorderLayout.EAST);
        frame.add(button5,BorderLayout.SOUTH);
        frame.setBounds(300,200,600,300);
        frame.setVisible(true);
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
    }
}

在該程序中分別指定了 BorderLayout 布局的東、南、西、北、中間區域中要填充的按鈕。該程序的運行結果如圖 2 所示。

填充5個區域的效果
圖2 填充5個區域的效果

如果未指定布局管理器的 NORTH 區域,即將“frame.add(button1,BorderLayout.NORTH);”注釋掉,則 WEST、CENTER 和 EAST 3 個區域將會填充 NORTH 區域,如圖 3 所示。

缺少 NORTH 區域
圖3 缺少NORTH區域

同理,如果未指定布局管理器的 WEST 區域,即將“frame.add(button2,BorderLayout.WEST);”注釋掉,則 CENTER 區域將會自動拉伸填充 WEST 區域,如圖 4 所示。

缺少 WEST 區域
圖4 缺少WEST區域

流式布局管理器

FlowLayout(流式布局管理器)是 JPanel 和 JApplet 的默認布局管理器。FlowLayout 會將組件按照從上到下、從左到右的放置規律逐行進行定位。與其他布局管理器不同的是,FlowLayout 布局管理器不限制它所管理組件的大小,而是允許它們有自己的最佳大小。

FlowLayout 布局管理器的構造方法如下。
  • FlowLayout():創建一個布局管理器,使用默認的居中對齊方式和默認 5 像素的水平和垂直間隔。
  • FlowLayout(int align):創建一個布局管理器,使用默認 5 像素的水平和垂直間隔。其中,align 表示組件的對齊方式,對齊的值必須是 FlowLayoutLEFT、FlowLayout.RIGHT 和 FlowLayout.CENTER,指定組件在這一行的位置是居左對齊、居右對齊或居中對齊。
  • FlowLayout(int align, int hgap,int vgap):創建一個布局管理器,其中 align 表示組件的對齊方式;hgap 表示組件之間的橫向間隔;vgap 表示組件之間的縱向間隔,單位是像素。

例 2

創建一個窗口,設置標題為“Java第四個GUI程序”。使用 FlowLayout 類對窗口進行布局,向容器內添加 9 個按鈕,并設置橫向和縱向的間隔都為 20 像素。具體實現代碼如下:
package ch17;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import java.awt.*;
public class FlowLayoutDemo
{
    public static void main(String[] agrs)
    {
        JFrame jFrame=new JFrame("Java第四個GUI程序");    //創建Frame窗口
        JPanel jPanel=new JPanel();    //創建面板
        JButton btn1=new JButton("1");    //創建按鈕
        JButton btn2=new JButton("2");
        JButton btn3=new JButton("3");
        JButton btn4=new JButton("4");
        JButton btn5=new JButton("5");
        JButton btn6=new JButton("6");
        JButton btn7=new JButton("7");
        JButton btn8=new JButton("8");
        JButton btn9=new JButton("9");
        jPanel.add(btn1);    //面板中添加按鈕
        jPanel.add(btn2);
        jPanel.add(btn3);
        jPanel.add(btn4);
        jPanel.add(btn5);
        jPanel.add(btn6);
        jPanel.add(btn7);
        jPanel.add(btn8);
        jPanel.add(btn9);
        //向JPanel添加FlowLayout布局管理器,將組件間的橫向和縱向間隙都設置為20像素
        jPanel.setLayout(new FlowLayout(FlowLayout.LEADING,20,20));
        jPanel.setBackground(Color.gray);    //設置背景色
        jFrame.add(jPanel);    //添加面板到容器
        jFrame.setBounds(300,200,300,150);    //設置容器的大小
        jFrame.setVisible(true);
        jFrame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
    }
}

上述程序向 JPanel 面板中添加了 9 個按鈕,并使用 HowLayout 布局管理器使 9 個按鈕間的橫向和縱向間隙都為 20 像素。此時這些按鈕將在容器上按照從上到下、從左到右的順序排列,如果一行剩余空間不足容納組件將會換行顯示,最終運行結果如圖 5 所示。

FlowLayout布局按鈕結果

FlowLayout布局按鈕結果
圖5 FlowLayout布局按鈕結果

卡片布局管理器

CardLayout(卡片布局管理器)能夠幫助用戶實現多個成員共享同一個顯不空間,并且一次只顯示一個容器組件的內容。

CardLayout 布局管理器將容器分成許多層,每層的顯示空間占據整個容器的大小,但是每層只允許放置一個組件。CardLayout 的構造方法如下。
  • CardLayout():構造一個新布局,默認間隔為 0。
  • CardLayout(int hgap, int vgap):創建布局管理器,并指定組件間的水平間隔(hgap)和垂直間隔(vgap)。

例 3

使用 CardLayout 類對容器內的兩個面板進行布局。其中第一個面板上包括三個按鈕,第二個面板上包括三個文本框。最后調用 CardLayout 類的 show() 方法顯示指定面板的內容,代碼如下:
package ch17;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.JTextField;
import java.awt.*;
public class CardLayoutDemo
{   
    public static void main(String[] agrs)
    {
        JFrame frame=new JFrame("Java第五個程序");    //創建Frame窗口
        JPanel p1=new JPanel();    //面板1
        JPanel p2=new JPanel();    //面板2
        JPanel cards=new JPanel(new CardLayout());    //卡片式布局的面板
        p1.add(new JButton("登錄按鈕"));
        p1.add(new JButton("注冊按鈕"));
        p1.add(new JButton("找回密碼按鈕"));
        p2.add(new JTextField("用戶名文本框",20));
        p2.add(new JTextField("密碼文本框",20));
        p2.add(new JTextField("驗證碼文本框",20));
        cards.add(p1,"card1");    //向卡片式布局面板中添加面板1
        cards.add(p2,"card2");    //向卡片式布局面板中添加面板2
        CardLayout cl=(CardLayout)(cards.getLayout());
        cl.show(cards,"card1");    //調用show()方法顯示面板2
        frame.add(cards);
        frame.setBounds(300,200,400,200);
        frame.setVisible(true);
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
    }
}

上述代碼創建了一個卡片式布局的面板 cards,該面板包含兩個大小相同的子面板 p1 和 p2。需要注意的是,在將 p1 和 p2 添加到 cards 面板中時使用了含有兩個參數的 add() 方法,該方法的第二個參數用來標識子面板。當需要顯示某一個面板時,只需要調用卡片式布局管理器的 show() 方法,并在參數中指定子面板所對應的字符串即可,這里顯示的是 p1 面板,運行效果如圖 6 所示。

顯示 p1 面板
圖6 顯示p1面板   

如果將“cl.show(cards,"card1")”語句中的 card1 換成 card2,將顯示 p2 面板的內容,此時運行結果如圖 7 所示。

顯示 p2 面板
圖7 顯示p2面板

網格布局管理器

GridLayout(網格布局管理器)為組件的放置位置提供了更大的靈活性。它將區域分割成行數(rows)和列數(columns)的網格狀布局,組件按照由左至右、由上而下的次序排列填充到各個單元格中。

GridLayout 的構造方法如下。
  • GridLayout(int rows,int cols):創建一個指定行(rows)和列(cols)的網格布局。布局中所有組件的大小一樣,組件之間沒有間隔。
  • GridLayout(int rows,int cols,int hgap,int vgap):創建一個指定行(rows)和列(cols)的網格布局,并且可以指定組件之間橫向(hgap)和縱向(vgap)的間隔,單位是像素。

提示:GridLayout 布局管理器總是忽略組件的最佳大小,而是根據提供的行和列進行平分。該布局管理的所有單元格的寬度和高度都是一樣的。

例 4

使用 GridLayout 類的網格布局設計一個簡單計算器。代碼的實現如下:
package ch17;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.JTextField;
import java.awt.*;
public class GridLayoutDemo
{
    public static void main(String[] args)
    {
        JFrame frame=new JFrame("GridLayou布局計算器");
        JPanel panel=new JPanel();    //創建面板
        //指定面板的布局為GridLayout,4行4列,間隙為5
        panel.setLayout(new GridLayout(4,4,5,5));
        panel.add(new JButton("7"));    //添加按鈕
        panel.add(new JButton("8"));
        panel.add(new JButton("9"));
        panel.add(new JButton("/"));
        panel.add(new JButton("4"));
        panel.add(new JButton("5"));
        panel.add(new JButton("6"));
        panel.add(new JButton("*"));
        panel.add(new JButton("1"));
        panel.add(new JButton("2"));
        panel.add(new JButton("3"));
        panel.add(new JButton("-"));
        panel.add(new JButton("0"));
        panel.add(new JButton("."));
        panel.add(new JButton("="));
        panel.add(new JButton("+"));
        frame.add(panel);    //添加面板到容器
        frame.setBounds(300,200,200,150);
        frame.setVisible(true);
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
    }
}

上述程序設置面板為 4 行 4 列、間隙都為 5 像素的網格布局,在該面板上包含 16 個按鈕,其橫向和縱向的間隙都為 5。該程序的運行結果如圖 8 所示。

計算器
圖8 計算器

網格包布局管理器

GridBagLayout(網格包布局管理器)是在網格基礎上提供復雜的布局,是最靈活、 最復雜的布局管理器。GridBagLayout 不需要組件的尺寸一致,允許組件擴展到多行多列。每個 GridBagLayout 對象都維護了一組動態的矩形網格單元,每個組件占一個或多個單元,所占有的網格單元稱為組件的顯示區域。

GridBagLayout 所管理的每個組件都與一個 GridBagConstraints 約束類的對象相關。這個約束類對象指定了組件的顯示區域在網格中的位置,以及在其顯示區域中應該如何擺放組件。除了組件的約束對象,GridBagLayout 還要考慮每個組件的最小和首選尺寸,以確定組件的大小。

為了有效地利用網格包布局管理器,在向容器中添加組件時,必須定制某些組件的相關約束對象。GridBagConstraints 對象的定制是通過下列變量實現的。

1. gridx 和 gridy

用來指定組件左上角在網格中的行和列。容器中最左邊列的 gridx 為 0,最上邊行的 gridy 為 0。這兩個變量的默認值是 GridBagConstraints.RELATIVE,表示對應的組件將放在前一個組件的右邊或下面。

2. gridwidth 和 gridheight

用來指定組件顯示區域所占的列數和行數,以網格單元而不是像素為單位,默認值為 1。

3. fill

指定組件填充網格的方式,可以是如下值:GridBagConstraints.NONE(默認值)、GridBagConstraints.HORIZONTAL(組件橫向充滿顯示區域,但是不改變組件高度)、GridBagConstraints.VERTICAL(組件縱向充滿顯示區域,但是不改變組件寬度)以及 GridBagConstraints.BOTH(組件橫向、縱向充滿其顯示區域)。

4. ipadx 和 ipady

指定組件顯示區域的內部填充,即在組件最小尺寸之外需要附加的像素數,默認值為 0。

5. insets

指定組件顯示區域的外部填充,即組件與其顯示區域邊緣之間的空間,默認組件沒有外部填充。

6. anchor

指定組件在顯示區域中的擺放位置。可選值有 GridBagConstraints.CENTER(默認值)、GridBagConstraints.NORTH、GridBagConstraints.
NORTHEAST、GridBagConstraints.EAST、GridBagConstraints.SOUTH、GridBagConstraints.SOUTHEAST、GridBagConstraints.WEST、GridBagConstraints.SOUTHWEST 以及 GridBagConstraints.NORTHWEST。

7. weightx 和 weighty

用來指定在容器大小改變時,增加或減少的空間如何在組件間分配,默認值為 0,即所有的組件將聚攏在容器的中心,多余的空間將放在容器邊緣與網格單元之間。weightx 和 weighty 的取值一般在 0.0 與 1.0 之間,數值大表明組件所在的行或者列將獲得更多的空間。

例 5

創建一個窗口,使用 GridBagLayout 進行布局,實現一個簡易的手機撥號盤。這里要注意如何控制行內組件的顯示方式以及使用 GridBagConstraints.REMAINDER 來控制一行的結束。代碼的實現如下:
package ch17;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.JTextField;
import java.awt.*;
public class GridBagLayoutDemo
{
    //向JFrame中添加JButton按鈕
    public static void makeButton(String title,JFrame frame,GridBagLayout gridBagLayout,GridBagConstraints constraints)
    {   
        JButton button=new JButton(title);    //創建Button對象
        gridBagLayout.setConstraints(button,constraints);
        frame.add(button);
    }
    public static void main(String[] agrs)
    {
        JFrame frame=new JFrame("撥號盤");
        GridBagLayout gbaglayout=new GridBagLayout();    //創建GridBagLayout布局管理器
        GridBagConstraints constraints=new GridBagConstraints();
        frame.setLayout(gbaglayout);    //使用GridBagLayout布局管理器
        constraints.fill=GridBagConstraints.BOTH;    //組件填充顯示區域
        constraints.weightx=0.0;    //恢復默認值
        constraints.gridwidth = GridBagConstraints.REMAINDER;    //結束行
        JTextField tf=new JTextField("13612345678");
        gbaglayout.setConstraints(tf, constraints);
        frame.add(tf);
        constraints.weightx=0.5;    // 指定組件的分配區域
        constraints.weighty=0.2;
        constraints.gridwidth=1;
        makeButton("7",frame,gbaglayout,constraints);    //調用方法,添加按鈕組件
        makeButton("8",frame,gbaglayout,constraints);
        constraints.gridwidth=GridBagConstraints.REMAINDER;    //結束行
        makeButton("9",frame,gbaglayout,constraints);
        constraints.gridwidth=1;    //重新設置gridwidth的值
       
        makeButton("4",frame,gbaglayout,constraints);
        makeButton("5",frame,gbaglayout,constraints);
        constraints.gridwidth=GridBagConstraints.REMAINDER;
        makeButton("6",frame,gbaglayout,constraints);
        constraints.gridwidth=1;
       
        makeButton("1",frame,gbaglayout,constraints);
        makeButton("2",frame,gbaglayout,constraints);
        constraints.gridwidth=GridBagConstraints.REMAINDER;
        makeButton("3",frame,gbaglayout,constraints);
        constraints.gridwidth=1;
       
        makeButton("返回",frame,gbaglayout,constraints);
        constraints.gridwidth=GridBagConstraints.REMAINDER;
        makeButton("撥號",frame,gbaglayout,constraints);
        constraints.gridwidth=1;
        frame.setBounds(400,400,400,400);    //設置容器大小
        frame.setVisible(true);
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
    }
}

在上述程序中創建了一個 makeButton() 方法,用來將 JButton 組件添加到 JFrame 窗口中。在 main() 方法中分別創建了 GridBagLayout 對象和 GridBagConstraints 對象,然后設置 JFrame 窗口的布局為 GridBagLayout,并設置了 GridBagConstraints 的一些屬性。接著將 JTextField 組件添加至窗口中,并通知布局管理器的 GridBagConstraints 信息。

在接下來的代碼中,調用 makeButton() 方法向 JFrame 窗口填充按鈕,并使用 GridBagConstraints. REMAINDER 來控制結束行。當一行結束后,重新設置 GridBagConstraints 對象的 gridwidth 為 1。最后設置 JFrame 窗口為可見狀態,程序運行后的撥號盤效果如圖 9 所示。

撥號盤運行效果
圖9 撥號盤運行效果

盒布局管理器

BoxLayout(盒布局管理器)通常和 Box 容器聯合使用,Box 類有以下兩個靜態方法。
  • createHorizontalBox():返回一個 Box 對象,它采用水平 BoxLayout,即 BoxLayout 沿著水平方向放置組件,讓組件在容器內從左到右排列。
  • createVerticalBox():返回一個 Box 對象,它采用垂直 BoxLayout,即 BoxLayout 沿著垂直方向放置組件,讓組件在容器內從上到下進行排列。

Box 還提供了用于決定組件之間間隔的靜態方法,如表 1 所示。

表1 Box類設置組件間隔的靜態方法
網格包布局 說明
static Component createHorizontalGlue() 創建一個不可見的、可以被水平拉伸和收縮的組件
static Component createVerticalGlue() 創建一個不可見的、可以被垂直拉伸和收縮的組件
static Component createHorizontalStrut(int width) 創建一個不可見的、固定寬度的組件
static Component createVerticalStrut(int height) 創建一個不可見的、固定高度的組件
static Component createRigidArea(Dimension d) 創建一個不可見的、總是具有指定大小的組件

BoxLayout 類只有一個構造方法,如下所示。
BoxLayout(Container c,int axis)

其中,參數 Container 是一個容器對象,即該布局管理器在哪個容器中使用;第二個參數為 int 型,用來決定容器上的組件水平(X_AXIS)或垂直(Y_AXIS)放置,可以使用 BoxLayout 類訪問這兩個屬性。

例 6

使用 BoxLayout 類對容器內的 4  個按鈕進行布局管理,使兩個按鈕為橫向排列,另外兩個按鈕為縱向排列,代碼如下:
package ch17;
import javax.swing.Box;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.JTextField;
import java.awt.*;
public class BoxLayoutDemo
{
    public static void main(String[] agrs)
    {
        JFrame frame=new JFrame("Java示例程序");
        Box b1=Box.createHorizontalBox();    //創建橫向Box容器
        Box b2=Box.createVerticalBox();    //創建縱向Box容器
        frame.add(b1);    //將外層橫向Box添加進窗體
        b1.add(Box.createVerticalStrut(200));    //添加高度為200的垂直框架
        b1.add(new JButton("西"));    //添加按鈕1
        b1.add(Box.createHorizontalStrut(140));    //添加長度為140的水平框架 
        b1.add(new JButton("東"));    //添加按鈕2
        b1.add(Box.createHorizontalGlue());    //添加水平膠水
        b1.add(b2);    //添加嵌套的縱向Box容器
        //添加寬度為100,高度為20的固定區域  
        b2.add(Box.createRigidArea(new Dimension(100,20))); 
        b2.add(new JButton("北"));    //添加按鈕3
        b2.add(Box.createVerticalGlue());    //添加垂直組件
        b2.add(new JButton("南"));    //添加按鈕4
        b2.add(Box.createVerticalStrut(40));    //添加長度為40的垂直框架
        //設置窗口的關閉動作、標題、大小位置以及可見性等  
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); 
        frame.setBounds(100,100,400,200); 
        frame.setVisible(true); 
    }
}

在程序中創建了 4 個 JButton 按鈕和兩個 Box 容器(橫向 Box 容器和縱向 Box 容器),并將前兩個 JButton 按鈕添加到橫向 Box 容器中,將后兩個 JButton 容器添加到縱向 Box 容器中。程序的運行結果如圖 10 所示。

BoxLayout運行結果
圖10 BoxLayout運行結果

提示:使用盒式布局可以像使用流式布局一樣簡單地將組件安排在一個容器內。包含盒式布局的容器可以嵌套使用,最終達到類似于無序網格布局那樣的效果,卻不像使用無序網格布局那樣麻煩。

精美而實用的網站,提供C語言、C++、STL、Linux、Shell、Java、Go語言等教程,以及socket、GCC、vi、Swing、設計模式、JSP等專題。

Copyright ?2011-2018 biancheng.net, 陜ICP備15000209號

底部Logo