【從零開始學 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 線上教室,臉書粉絲團,會不定期發佈相關資訊,不想錯過最新資訊,不要忘記來按讚,加追蹤喔!也歡迎大家將這套課程分享給更多人喔。
我們下次再見囉!!!掰掰~

這個網誌中的熱門文章

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

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

nano 文字編輯器

2022 最新入門零基礎 Flutter教學 【Flutter 程式設計入門實戰 30 天】Flutter 教學課程目錄 (IntelliJ IDEA 開發教學)

Android Studio 歷代版本下載點