GridLayout 是 SWT 功能最強大、最常用的佈局管理器。它將容器劃分為網格(行×列),每個子元件佔據一或多個儲存格,支援跨行跨列、四向對齊、空間搶佔、固定/最小/建議尺寸、邊距間距等精細控制,適合複雜對話框、表單、響應式視窗。
| 屬性 | 類型 | 預設 | 說明 |
|---|---|---|---|
numColumns | int | 1 | 欄數(列數由元件數量自動決定) |
makeColumnsEqualWidth | boolean | false | true=所有欄位寬度相同(以最寬者為準) |
marginLeft/Right/Top/Bottom | int | 5 | 容器四邊留白 |
horizontalSpacing | int | 5 | 欄與欄之間間距 |
verticalSpacing | int | 5 | 列與列之間間距 |
建構子 new GridLayout(int numColumns, boolean makeColumnsEqualWidth) 可一次設定核心參數。
每個子元件可透過 setLayoutData(GridData) 指定在網格中的行為。GridData 提供豐富屬性:
| 屬性 | 說明 | 常用常數 |
|---|---|---|
horizontalAlignment | 水平對齊 | BEGINNING, CENTER, END, FILL |
verticalAlignment | 垂直對齊 | BEGINNING, CENTER, END, FILL |
horizontalIndent | 水平縮進 (像素),需配合 BEGINNING | int |
horizontalSpan | 跨越欄數 | int (≥1) |
verticalSpan | 跨越列數 | int (≥1) |
grabExcessHorizontalSpace | 容器加寬時是否搶佔額外空間 | boolean |
grabExcessVerticalSpace | 容器增高時是否搶佔額外空間 | boolean |
widthHint | 建議寬度 (像素),若未設 grab/FILL 則生效 | int |
heightHint | 建議高度 (像素) | int |
minimumWidth/Height | 最小尺寸限制 | int |
建構子多載:new GridData()、new GridData(int hAlign)、new GridData(int hAlign, int vAlign, boolean grabH, boolean grabV)、new GridData(int hAlign, int vAlign, boolean grabH, boolean grabV, int hSpan, int vSpan)。
GridLayout gl = new GridLayout(2, true); // 2欄、等寬
shell.setLayout(gl);
Button b1 = new Button(shell, SWT.PUSH); b1.setText("button1");
b1.setLayoutData(new GridData(GridData.VERTICAL_ALIGN_BEGINNING));
List list = new List(shell, SWT.BORDER);
list.add("item 1"); list.add("item 2"); list.add("item 3");
list.setLayoutData(new GridData(GridData.VERTICAL_ALIGN_CENTER));
Button b2 = new Button(shell, SWT.PUSH); b2.setText("button #2");
GridData gd = new GridData(GridData.VERTICAL_ALIGN_END);
gd.horizontalIndent = 5; b2.setLayoutData(gd);
Button b3 = new Button(shell, SWT.PUSH); b3.setText("3");
b3.setLayoutData(new GridData(GridData.VERTICAL_ALIGN_FILL)); // 垂直填滿
shell.pack(); shell.open();
觀察: 四個元件依序填入 2×2 網格。verticalAlignment 控制各元件在儲存格內的垂直位置;horizontalIndent 讓 b2 向右縮進 5px。
GridLayout gl = new GridLayout(3, false);
shell.setLayout(gl);
Label label = new Label(shell, SWT.BORDER); label.setText("label");
GridData gd3 = new GridData(); gd3.widthHint=60; gd3.heightHint=20; label.setLayoutData(gd3);
Text text = new Text(shell, SWT.SINGLE | SWT.BORDER); text.setText("text");
GridData gd = new GridData();
gd.grabExcessHorizontalSpace = true; gd.grabExcessVerticalSpace = true;
gd.horizontalAlignment = GridData.FILL; gd.verticalAlignment = GridData.FILL;
text.setLayoutData(gd);
Button btn = new Button(shell, SWT.PUSH); btn.setText("button");
GridData gd2 = new GridData();
gd2.grabExcessHorizontalSpace = true; gd2.grabExcessVerticalSpace = true;
gd2.horizontalAlignment = GridData.FILL; gd2.verticalAlignment = GridData.FILL;
btn.setLayoutData(gd2);
shell.setSize(300, 80); shell.open();
效果: 拉大視窗時,Text 與 Button 平均瓜分額外空間(皆 grab=true、FILL);Label 保持固定 60×20。若僅 Text grab=true,Text 獨佔額外空間。
GridLayout gl = new GridLayout(2, true);
shell.setLayout(gl);
Button b1 = new Button(shell, SWT.PUSH); b1.setText("button1");
b1.setLayoutData(new GridData(GridData.VERTICAL_ALIGN_BEGINNING));
List list = new List(shell, SWT.BORDER); // 佔據 (row1, col1)
list.add("item 1"); list.add("item 2"); list.add("item 3");
list.setLayoutData(new GridData(GridData.VERTICAL_ALIGN_CENTER));
Button b2 = new Button(shell, SWT.PUSH); b2.setText("button #2");
GridData gd = new GridData(GridData.VERTICAL_ALIGN_END);
gd.horizontalSpan = 2; gd.horizontalAlignment = GridData.FILL; // 橫跨 2 欄
b2.setLayoutData(gd);
Button b3 = new Button(shell, SWT.PUSH); b3.setText("3");
GridData gd2 = new GridData(GridData.VERTICAL_ALIGN_END);
gd2.verticalSpan = 3; // 縱跨 3 列
b3.setLayoutData(gd2);
shell.pack(); shell.open();
網格佈局圖:
[ b1 ] [ list ] [ b2 (span2) ] [ list ] [ b3 (vSpan3)] [ list ] [ b3 ] [ ] [ b3 ] [ ]
shell.setText("Book Entry Demo");
GridLayout gl = new GridLayout(4, false);
gl.verticalSpacing = 8; shell.setLayout(gl);
// Title: 標籤 + 文字框跨 3 欄
new Label(shell, SWT.NONE).setText("Title: ");
Text title = new Text(shell, SWT.SINGLE | SWT.BORDER);
GridData gd = new GridData(GridData.HORIZONTAL_ALIGN_FILL); gd.horizontalSpan = 3; title.setLayoutData(gd);
// Author: 標籤 + 文字框跨 3 欄
new Label(shell, SWT.NONE).setText("Author(s): ");
Text authors = new Text(shell, SWT.SINGLE | SWT.BORDER);
gd = new GridData(GridData.HORIZONTAL_ALIGN_FILL); gd.horizontalSpan = 3; authors.setLayoutData(gd);
// Cover: 標籤縱跨 3 列 + CLabel 縱跨 3 列、固定 100x100
new Label(shell, SWT.NONE).setText("Cover: ");
GridData gdL = new GridData(); gdL.verticalSpan = 3; new Label(shell, SWT.NONE).setLayoutData(gdL);
CLabel cover = new CLabel(shell, SWT.BORDER);
gd = new GridData(GridData.FILL_HORIZONTAL); gd.horizontalSpan = 1; gd.verticalSpan = 3;
gd.heightHint = 100; gd.widthHint = 100; cover.setLayoutData(gd);
// Pages / Publisher / Rating: 三欄標籤 + 三欄輸入
String[] labels = {"Pages", "Publisher", "Rating"};
for (String lb : labels) new Label(shell, SWT.NONE).setText(lb + ": ");
Text pages = new Text(shell, SWT.SINGLE | SWT.BORDER);
pages.setLayoutData(new GridData(GridData.HORIZONTAL_ALIGN_FILL));
Text pub = new Text(shell, SWT.SINGLE | SWT.BORDER);
pub.setLayoutData(new GridData(GridData.HORIZONTAL_ALIGN_FILL));
Combo rating = new Combo(shell, SWT.READ_ONLY);
rating.setLayoutData(new GridData(GridData.HORIZONTAL_ALIGN_FILL));
rating.add("5"); rating.add("4"); rating.add("3"); rating.add("2"); rating.add("1");
// Abstract: 標籤 + 多行文字框跨 3 欄、垂直搶佔空間
new Label(shell, SWT.NONE).setText("Abstract:");
Text abs = new Text(shell, SWT.WRAP | SWT.MULTI | SWT.BORDER | SWT.H_SCROLL | SWT.V_SCROLL);
gd = new GridData(GridData.HORIZONTAL_ALIGN_FILL | GridData.VERTICAL_ALIGN_FILL);
gd.horizontalSpan = 3; gd.grabExcessVerticalSpace = true; abs.setLayoutData(gd);
// Enter 按鈕:跨 4 欄、靠右
Button enter = new Button(shell, SWT.PUSH); enter.setText("Enter");
gd = new GridData(); gd.horizontalSpan = 4; gd.horizontalAlignment = GridData.END; enter.setLayoutData(gd);
// 設定測試資料
title.setText("Professional Java Interfaces with SWT/JFace");
authors.setText("Jack Li Guojie"); pages.setText("500pp");
pub.setText("John Wiley & Sons");
cover.setBackground(new Image(display, "C:/eclipse32.gif"));
abs.setText("This book provides a comprehensive guide for\nyou to create Java user interfaces with SWT/JFace.");
shell.pack(); shell.open();
此範例展示實戰中常見的:標籤+輸入配對、跨欄輸入框、圖片區域固定尺寸跨列、多行文字區域垂直擴展、按鈕靠右對齊。
parent.layout(true) 重新計算;若尺寸需變更再 parent.pack()。GridData.minimumWidth/Height 防止元件被壓縮過小。makeColumnsEqualWidth=true 適合按鈕列、標籤欄;輸入框區域建議 false。| 現象 | 原因 | 解決 |
|---|---|---|
| 元件重疊 | Span 計算錯誤導致儲存格衝突 | 檢查 horizontalSpan/verticalSpan 總和不超過 numColumns/行數 |
| 元件不顯示 | 未呼叫 setLayoutData 或 GridData 設定錯誤 | 每個子元件必須 setLayoutData;檢查 grab/FILL 組合 |
| 空間分配不均 | 多欄 grabExcessHorizontalSpace=true 但寬度提示不同 | 統一 widthHint 或移除 hint 讓建議尺寸決定初始比例 |
| 垂直置中失效 | 容器高度未撐開(無 grabExcessVerticalSpace) | 父容器或祖先需 grabExcessVerticalSpace=true 且 FILL |
| 場景 | 推薦佈局 | 理由 |
|---|---|---|
| 單一元件填滿視窗 | FillLayout | 最簡單、零配置 |
| 工具列、按鈕群、簡單流式排列 | RowLayout | 支援換行、固定尺寸、邊距 |
| 表單、對話框、精細對齊、響應式 | GridLayout | 網格化、Span、Grab、四向對齊、最完整 |
| 極度精確像素級定位、重疊、動畫 | 無佈局 | 手動 setBounds,罕見需求 |
GridLayout + GridData 是 SWT 佈局系統的核心與精華。掌握 numColumns、Span、Alignment、GrabExcessSpace、Hint/Minimum 五大維度,即可構建出專業級、響應式、可維護的複雜 UI。建議開發者熟練掌握 GridLayout,作為日常開發的首選佈局管理器。