【從零開始學 Java 程式設計】 進階佈局管理器 - GridBagLayout

【從零開始學 Java 程式設計】 線上教學課程目錄,使用 Java 程式語言,開發應用程式。

GridBagLayout

GridBagLayout 網格群佈局,透過元件加入容器時使用 GridBagConstraints 設定相關參數來進行佈局。共有以下這些參數進行設定:

gridx, gridy

用來指定元件將擺放在網格中的哪一行和哪一列當中。最左上角第一格為 gridx = 0, gridy = 0。
  • 元件A
    gridx = 0
    gridy = 0
  • 元件B
    gridx = 3
    gridy = 2
  • 元件C
    gridx = 4
    gridy = 5

gridwidth, gridheight

用來指定元件顯示區域所佔的列數和行數,以網格為單位而不是像素為單位,預設值值為 1,佔用一個網格。
  • 元件A
    gridx = 0
    gridy = 0
    gridwidth = 1
    gridheight = 1
  • 元件B
    gridx = 3
    gridy = 2
    gridwidth = 2
    gridheight = 1
  • 元件C
    gridx = 4
    gridy = 4
    gridwidth = 2
    gridheight = 2

fill

用來指定元件填充網格的方式。
GridBagConstraints.NONE(預設值)
GridBagConstraints.HORIZONTAL (以水平填充其顯示區域)
GridBagConstraints.VERTICAL (以垂直填充其顯示區域)
GridBagConstraints.BOTH (完全填充其顯示區域)
  • 元件A
    gridx = 0
    gridy = 0
    gridwidth = 2
    gridheight = 2
    fill = GridBagConstraints.NONE
  • 元件B
    gridx = 3
    gridy = 2
    gridwidth = 2
    gridheight = 2
    fill = GridBagConstraints.HORIZONTAL
  • 元件C
    gridx = 4
    gridy = 4
    gridwidth = 2
    gridheight = 2
    fill = GridBagConstraints.VERTICAL
  • 元件D
    gridx = 4
    gridy = 4
    gridwidth = 2
    gridheight = 2
    fill = GridBagConstraints.BOTH

ipadx, ipady

用來指定元件顯示區域的內部填充,即在元件最小尺寸之外需要附加的像素值,預設值為0。
拉大元件大小 ipadx、ipady 為正值,如:10
縮小元件大小 ipadx、ipady 為負值,如:-10

insets

用來指定元件的外部填充,即元件與其顯示區域邊緣之間的間距(元件上下左右間距)。

anchor

用來指定元件在顯示區域中的擺放位置。
  • 絕對值
    GridBagConstraints.NORTH
    GridBagConstraints.SOUTH
    GridBagConstraints.WEST
    GridBagConstraints.EAST
    GridBagConstraints.NORTHWEST
    GridBagConstraints.NORTHEAST
    GridBagConstraints.SOUTHWEST
    GridBagConstraints.SOUTHEAST
    GridBagConstraints.CENTER (預設)
  • 方向相對值
    GridBagConstraints.PAGE_START
    GridBagConstraints.PAGE_END
    GridBagConstraints.LINE_START
    GridBagConstraints.LINE_END
    GridBagConstraints.FIRST_LINE_START
    GridBagConstraints.FIRST_LINE_END
    GridBagConstraints.LAST_LINE_START
    GridBagConstraints.LAST_LINE_END
  • 基線相對值
    GridBagConstraints.BASELINE
    GridBagConstraints.BASELINE_LEADING
    GridBagConstraints.BASELINE_TRAILING
    GridBagConstraints.ABOVE_BASELINE
    GridBagConstraints.ABOVE_BASELINE_LEADING
    GridBagConstraints.ABOVE_BASELINE_TRAILING
    GridBagConstraints.BELOW_BASELINE
    GridBagConstraints.BELOW_BASELINE_LEADING
    GridBagConstraints.BELOW_BASELINE_TRAILIN

weightx, weighty

用來指定在容器大小改變時,增加或減少元件中的的空間分配。weightx (行)和weighty(列)的值一般在0.0與1.0之間,預設值為0,數值越大代表組件所在的行或者列將獲得更多的空間。
預設值為0,視窗拉大、縮小都不變化元件大小
設定 weightx, weighty 將會根據比例變化大小

範例一

練習透過 gridx 和 gridy 指定按鈕位置
public void addComponentsToPane(Container pane) {
        
    //宣告 GridBagLayout
    GridBagLayout gridBagLayout = new GridBagLayout();

    //設定佈局方式為 GridBagLayout
    pane.setLayout(gridBagLayout);

    //宣告網格約束變數
    GridBagConstraints c;

    //宣告按鈕變數
    JButton btn;

    //新增一個按鈕,並設定網格約束
    btn = new JButton("btn1");
    c = new GridBagConstraints();
    c.fill = GridBagConstraints.HORIZONTAL;
    c.gridx = 0;
    c.gridy = 0;
    pane.add(btn, c);

    //新增一個按鈕,並設定網格約束
    btn = new JButton("btn2");
    c = new GridBagConstraints();
    c.fill = GridBagConstraints.HORIZONTAL;
    c.gridx = 1;
    c.gridy = 1;
    pane.add(btn, c);

    //新增一個按鈕,並設定網格約束
    btn = new JButton("btn3");
    c = new GridBagConstraints();
    c.fill = GridBagConstraints.HORIZONTAL;
    c.gridx = 2;
    c.gridy = 2;
    pane.add(btn, c);
}

範例二

承上面範例,修改 gridwidth,讓 btn3 佔滿三格網格。
注意的是,除了 gridwidth=3 外,還要搭配 gridx 和 gridy 修改,否則無法佔滿三格。
btn = new JButton("btn3");
c.fill = GridBagConstraints.HORIZONTAL;
c.gridwidth = 3; //佔用三格,需要 gridx 和 gridy 搭配
c.gridx = 0;
c.gridy = 2;
pane.add(btn, c);

範例三

承上面範例,修改 ipady ,讓 btn2 長高變大顆長按鈕。(如果是調整 ipadx,則會讓按鈕長胖左右變大)。
btn = new JButton("btn2");
c = new GridBagConstraints();
c.fill = GridBagConstraints.HORIZONTAL;
c.ipady = 100; //長高變長按鈕
//c.ipadx = 100;
c.gridx = 1;
c.gridy = 1;
pane.add(btn, c);

範例四

承上面範例,修改 insets ,讓 btn3 ,與上面元件間距拉大。
btn = new JButton("btn3");
c = new GridBagConstraints();
c.fill = GridBagConstraints.HORIZONTAL;
c.gridwidth = 3;
c.insets = new Insets(100,0,0,0);//調整間距
c.gridx = 2;
c.gridy = 2;
pane.add(btn, c);

範例五

預設為GridBagConstraints.RELATIVE 情況下,元件會一個接一個使用排序下去,練習透過 REMAINDER 結束一行來佈局,新增的元件在將在下一行接續下去。
public void makeButton(Container pane, String title, GridBagLayout gridBagLayout, GridBagConstraints constraints) {
        JButton button = new JButton(title);     //創建Button對象
        gridBagLayout.setConstraints(button, constraints);
        pane.add(button);
}

public void addComponentsToPane(Container pane) {

    //宣告 GridBagLayout
    GridBagLayout gridBagLayout = new GridBagLayout();

    //設定佈局方式為 GridBagLayout
    pane.setLayout(gridBagLayout);

    //宣告網格約束變數
    GridBagConstraints c;

    JTextField jTextField = new JTextField();
    c = new GridBagConstraints();
    c.fill = GridBagConstraints.HORIZONTAL;
    c.ipady = 10;
    c.gridwidth = GridBagConstraints.REMAINDER;//第一列,結束行
    pane.add(jTextField, c);


    c = new GridBagConstraints();
    c.fill = GridBagConstraints.HORIZONTAL;
    c.ipady = 50;
    makeButton(pane, "btn1", gridBagLayout, c);
    makeButton(pane, "btn2", gridBagLayout, c);
    c.gridwidth = GridBagConstraints.REMAINDER;//第二列,結束行
    makeButton(pane, "btn3", gridBagLayout, c);

    c = new GridBagConstraints();
    c.fill = GridBagConstraints.HORIZONTAL;
    c.ipady = 50;
    makeButton(pane, "btn4", gridBagLayout, c);
    makeButton(pane, "btn5", gridBagLayout, c);
    c.gridwidth = GridBagConstraints.REMAINDER;//第三列,結束行
    makeButton(pane, "btn6", gridBagLayout, c);

    c = new GridBagConstraints();
    c.fill = GridBagConstraints.HORIZONTAL;
    c.ipady = 50;
    makeButton(pane, "btn7", gridBagLayout, c);
    makeButton(pane, "btn8", gridBagLayout, c);
    c.gridwidth = GridBagConstraints.REMAINDER;//第四列,結束行
    makeButton(pane, "btn9", gridBagLayout, c);

    c = new GridBagConstraints();
    c.fill = GridBagConstraints.HORIZONTAL;
    c.ipady = 50;
    makeButton(pane, "btn10", gridBagLayout, c);
    c = new GridBagConstraints();
    c.fill = GridBagConstraints.HORIZONTAL;
    c.gridwidth = 2;
    c.ipady = 50;
    makeButton(pane, "btn11", gridBagLayout, c);
    c.gridwidth = GridBagConstraints.REMAINDER;//第五列,結束行

}

補充資料

12306訂票助手,即是採用 GridBagLayout 來完成如下方畫面,完整詳細程式碼,可以參考: github 源始碼
部分佈局程式碼
setExtendedState(JFrame.MAXIMIZED_BOTH);
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
setBounds(100, 100, 1051, 781);
m_contentPane = new JPanel();
setContentPane(m_contentPane);
GridBagLayout gbl_m_contentPane = new GridBagLayout();
gbl_m_contentPane.columnWidths = new int[] { 1024, 0 };
gbl_m_contentPane.rowHeights = new int[] { 50, 150, 126, 39, 148, 0 };
gbl_m_contentPane.columnWeights = new double[] { 1.0, Double.MIN_VALUE };
gbl_m_contentPane.rowWeights = new double[] { 0.0, 0.0, 0.0, 0.0, 1.0, Double.MIN_VALUE };
m_contentPane.setLayout(gbl_m_contentPane);

panel_4 = new JPanel();
GridBagConstraints gbc_panel_4 = new GridBagConstraints();
gbc_panel_4.fill = GridBagConstraints.BOTH;
gbc_panel_4.insets = new Insets(0, 0, 5, 0);
gbc_panel_4.gridx = 0;
gbc_panel_4.gridy = 0;
m_contentPane.add(panel_4, gbc_panel_4);
panel_4.setBorder(new TitledBorder(UIManager.getBorder("TitledBorder.border"),
    "\u7B2C\u4E00\u6B65\uFF1A\u8F93\u5165\u4E58\u8F66\u4FE1\u606F", TitledBorder.LEADING, TitledBorder.TOP,
    null, null));
GridBagLayout gbl_panel_4 = new GridBagLayout();
gbl_panel_4.columnWidths = new int[] { 68, 100, 54, 94, 0, 80, 77, 200, 0, 0 };
gbl_panel_4.rowHeights = new int[] { 37, 0 };
gbl_panel_4.columnWeights = new double[] { 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, Double.MIN_VALUE };
gbl_panel_4.rowWeights = new double[] { 0.0, Double.MIN_VALUE };
panel_4.setLayout(gbl_panel_4);

lblNewLabel_4 = new JLabel("起站");
GridBagConstraints gbc_lblNewLabel_4 = new GridBagConstraints();
gbc_lblNewLabel_4.insets = new Insets(0, 0, 0, 5);
gbc_lblNewLabel_4.anchor = GridBagConstraints.EAST;
gbc_lblNewLabel_4.gridx = 0;
gbc_lblNewLabel_4.gridy = 0;
panel_4.add(lblNewLabel_4, gbc_lblNewLabel_4);

textTrainFrom = new JTextField();
textTrainFrom.setToolTipText("必须填写精确的站点名称");
GridBagConstraints gbc_textTrainFrom = new GridBagConstraints();
gbc_textTrainFrom.insets = new Insets(0, 0, 0, 5);
gbc_textTrainFrom.fill = GridBagConstraints.HORIZONTAL;
gbc_textTrainFrom.gridx = 1;
gbc_textTrainFrom.gridy = 0;
panel_4.add(textTrainFrom, gbc_textTrainFrom);
textTrainFrom.setColumns(10);

lblNewLabel_5 = new JLabel("到站");
GridBagConstraints gbc_lblNewLabel_5 = new GridBagConstraints();
gbc_lblNewLabel_5.insets = new Insets(0, 0, 0, 5);
gbc_lblNewLabel_5.anchor = GridBagConstraints.EAST;
gbc_lblNewLabel_5.gridx = 2;
gbc_lblNewLabel_5.gridy = 0;
panel_4.add(lblNewLabel_5, gbc_lblNewLabel_5);

textTrainTo = new JTextField();
textTrainTo.setToolTipText("必须填写精确的站点名称");
GridBagConstraints gbc_textTrainTo = new GridBagConstraints();
gbc_textTrainTo.fill = GridBagConstraints.HORIZONTAL;
gbc_textTrainTo.insets = new Insets(0, 0, 0, 5);
gbc_textTrainTo.gridx = 3;
gbc_textTrainTo.gridy = 0;
panel_4.add(textTrainTo, gbc_textTrainTo);
textTrainTo.setColumns(10);

lblNewLabel_6 = new JLabel("乘车日期");
GridBagConstraints gbc_lblNewLabel_6 = new GridBagConstraints();
gbc_lblNewLabel_6.insets = new Insets(0, 0, 0, 5);
gbc_lblNewLabel_6.anchor = GridBagConstraints.EAST;
gbc_lblNewLabel_6.gridx = 4;
gbc_lblNewLabel_6.gridy = 0;
panel_4.add(lblNewLabel_6, gbc_lblNewLabel_6);

textPrimaryTrainDate = new JTextField();
textPrimaryTrainDate.setToolTipText("每次启动自动设定为当前日期20天后预售期");
GridBagConstraints gbc_textPrimaryTrainDate = new GridBagConstraints();
gbc_textPrimaryTrainDate.insets = new Insets(0, 0, 0, 5);
gbc_textPrimaryTrainDate.fill = GridBagConstraints.HORIZONTAL;
gbc_textPrimaryTrainDate.gridx = 5;
gbc_textPrimaryTrainDate.gridy = 0;
panel_4.add(textPrimaryTrainDate, gbc_textPrimaryTrainDate);
textPrimaryTrainDate.setColumns(10);

label = new JLabel("备选日期");
GridBagConstraints gbc_label = new GridBagConstraints();
gbc_label.anchor = GridBagConstraints.EAST;
gbc_label.insets = new Insets(0, 0, 0, 5);
gbc_label.gridx = 6;
gbc_label.gridy = 0;
panel_4.add(label, gbc_label);

textExtraTrainDates = new JTextField();
textExtraTrainDates.setToolTipText("主要用在指定多个日期刷“退票”");
textExtraTrainDates.setColumns(10);
GridBagConstraints gbc_textExtraTrainDates = new GridBagConstraints();
gbc_textExtraTrainDates.insets = new Insets(0, 0, 0, 5);
gbc_textExtraTrainDates.fill = GridBagConstraints.HORIZONTAL;
gbc_textExtraTrainDates.gridx = 7;
gbc_textExtraTrainDates.gridy = 0;
panel_4.add(textExtraTrainDates, gbc_textExtraTrainDates);

lblNewLabel = new JLabel("格式:按照预计乘车“日”优先级逗号分隔填写,如20,19,18,14");
GridBagConstraints gbc_lblNewLabel = new GridBagConstraints();
gbc_lblNewLabel.gridx = 8;
gbc_lblNewLabel.gridy = 0;
panel_4.add(lblNewLabel, gbc_lblNewLabel);

userPanelContainer = new JPanel();
userPanelContainer.setBorder(new TitledBorder(UIManager.getBorder("TitledBorder.border"),
    "\u7B2C\u4E8C\u6B65\uFF1A\u7528\u6237\u53CA\u8F66\u6B21\u8BBE\u7F6E", TitledBorder.LEADING,
    TitledBorder.TOP, null, null));
GridBagConstraints gbc_userPanelContainer = new GridBagConstraints();
gbc_userPanelContainer.fill = GridBagConstraints.BOTH;
gbc_userPanelContainer.insets = new Insets(0, 0, 5, 0);
gbc_userPanelContainer.gridx = 0;
gbc_userPanelContainer.gridy = 1;
m_contentPane.add(userPanelContainer, gbc_userPanelContainer);
userPanelContainer.setLayout(new GridLayout(0, 1, 0, 0));

passengerPanelContainer = new JPanel();
passengerPanelContainer.setBorder(new TitledBorder(UIManager.getBorder("TitledBorder.border"), "\u7B2C\u4E09\u6B65\uFF1A\u4E58\u8F66\u4EBA\u4FE1\u606F", TitledBorder.LEADING, TitledBorder.TOP, null, null));
GridBagConstraints gbc_passengerPanelContainer = new GridBagConstraints();
gbc_passengerPanelContainer.fill = GridBagConstraints.HORIZONTAL;
gbc_passengerPanelContainer.insets = new Insets(0, 0, 5, 0);
gbc_passengerPanelContainer.gridx = 0;
gbc_passengerPanelContainer.gridy = 2;
m_contentPane.add(passengerPanelContainer, gbc_passengerPanelContainer);

panelOperation = new JPanel();
GridBagConstraints gbc_panelOperation = new GridBagConstraints();
gbc_panelOperation.fill = GridBagConstraints.BOTH;
gbc_panelOperation.insets = new Insets(0, 0, 5, 0);
gbc_panelOperation.gridx = 0;
gbc_panelOperation.gridy = 3;
m_contentPane.add(panelOperation, gbc_panelOperation);
panelOperation.setLayout(new FlowLayout(FlowLayout.CENTER, 5, 5));

參考資料


那這次的課程就介紹到這邊囉~
順帶一提,KT 線上教室,臉書粉絲團,會不定期發佈相關資訊,不想錯過最新資訊,不要忘記來按讚,加追蹤喔!也歡迎大家將這套課程分享給更多人喔。
我們下次再見囉!!!掰掰~

這個網誌中的熱門文章

nano 文字編輯器

2023 最新入門零基礎 Kotlin教學【從零開始學 Kotlin 程式設計】Kotlin 教學課程目錄 (Android Kotlin, IntelliJ IDEA, Android Studio, Android APP 開發教學)

16天記下7000單字

最新入門零基礎 Java 教學【從零開始學 Java 程式設計】Java教學課程目錄 (IntelliJ IDEA 開發教學)

Android Studio 歷代版本下載點