FormLayout 是 SWT 中最靈活、功能最強大的佈局管理器。它不依賴固定網格,而是透過 FormAttachment 讓元件相對於父容器邊緣或其他元件進行精確定位。這使其成為構建複雜、響應式介面(如對話框、屬性頁、工具欄)的首選。
marginWidth、marginHeight)。FormAttachment(left, right, top, bottom)。| 建構子 | 參數 | 含義 |
|---|---|---|
new FormAttachment(int numerator) | 分子 (0~100) | 附著於父容器對應邊緣的百分比位置。 例: new FormAttachment(20) = 距左/上 20%。 |
new FormAttachment(Control control, int offset) | 參照元件, 偏移像素 | 附著於指定元件的對應邊緣(left 附著 left, top 附著 top),並偏移 offset 像素。 |
new FormAttachment(Control control, int offset, int alignment) | 參照元件, 偏移, 對齊常數 | 附著於指定元件的指定邊緣。 alignment: SWT.LEFT, RIGHT, TOP, BOTTOM, CENTER。例: new FormAttachment(btn, 0, SWT.CENTER) 置中對齊 btn。 |
public class FormLayoutSample {
public static void main(String[] args) {
Display display = new Display();
Shell shell = new Shell(display);
shell.setLayout(new FormLayout());
Button btn1 = new Button(shell, SWT.PUSH);
btn1.setText("button1");
FormData fd1 = new FormData();
fd1.left = new FormAttachment(20); // 距左 20%
fd1.top = new FormAttachment(20); // 距上 20%
btn1.setLayoutData(fd1);
Button btn2 = new Button(shell, SWT.PUSH);
btn2.setText("button number 2");
FormData fd2 = new FormData();
// btn2 左邊緣 附著於 btn1 水平置中線,偏移 0
fd2.left = new FormAttachment(btn1, 0, SWT.CENTER);
// btn2 上邊緣 附著於 btn1 垂直置中線,偏移 0
fd2.top = new FormAttachment(btn1, 0, SWT.CENTER);
btn2.setLayoutData(fd2);
shell.pack(); shell.open();
// ... 事件循環
}
}
結果:btn2 置中覆蓋在 btn1 上方(因兩者置中點相同)。
public class FormLayoutDialog {
public static void main(String[] args) {
Display display = new Display();
Shell shell = new Shell(display);
shell.setText("FormLayout Demo");
Label label = new Label(shell, SWT.WRAP);
label.setText("This is a long text string that will wrap when the dialog is resized.");
List list = new List(shell, SWT.BORDER | SWT.H_SCROLL | SWT.V_SCROLL);
list.setItems(new String[]{"Item 1", "Item 2", "Item 3", "Item 4"});
Button ok = new Button(shell, SWT.PUSH);
ok.setText("OK");
Button cancel = new Button(shell, SWT.PUSH);
cancel.setText("Cancel");
FormLayout layout = new FormLayout();
layout.marginWidth = 4;
layout.marginHeight = 4;
shell.setLayout(layout);
final int inset = 4;
// Label: 置頂,左右滿版
FormData labelData = new FormData();
labelData.left = new FormAttachment(0, 0);
labelData.right = new FormAttachment(100, 0);
label.setLayoutData(labelData);
// 動態調整 Label 寬度(換行支援)
shell.addListener(SWT.Resize, e -> {
Rectangle area = shell.getClientArea();
labelData.width = area.width - inset * 2;
shell.layout();
});
// Cancel: 右下角
FormData cancelData = new FormData();
cancelData.right = new FormAttachment(100, -inset);
cancelData.bottom = new FormAttachment(100, 0);
cancel.setLayoutData(cancelData);
// OK: Cancel 左側
FormData okData = new FormData();
okData.right = new FormAttachment(cancel, -inset);
okData.bottom = new FormAttachment(100, 0);
ok.setLayoutData(okData);
// List: 填滿 Label 下方到按鈕上方
FormData listData = new FormData();
listData.left = new FormAttachment(0, 0);
listData.right = new FormAttachment(100, 0);
listData.top = new FormAttachment(label, inset);
listData.bottom = new FormAttachment(cancel, -inset);
list.setLayoutData(listData);
shell.pack(); shell.open();
// ... 事件循環
}
}
// 左邊緣:父容器 30% + 10 像素
fd.left = new FormAttachment(30, 10);
// 右邊緣:父容器 70% - 5 像素
fd.right = new FormAttachment(70, -5);
// btnA -> btnB -> btnC 水平排列,等距 5px
fdA.right = new FormAttachment(btnB, -5);
fdB.left = new FormAttachment(btnA, 5);
fdB.right = new FormAttachment(btnC, -5);
fdC.left = new FormAttachment(btnB, 5);
// child 置中於 parent 內部
fd.left = new FormAttachment(parent, 0, SWT.CENTER);
fd.top = new FormAttachment(parent, 0, SWT.CENTER);
// 固定寬 200px:left 固定,right = left + 200
fd.left = new FormAttachment(10, 0);
fd.right = new FormAttachment(fd.left, 200); // 錯誤!FormAttachment 不能參照同一 FormData
// 正確做法:使用 widthHint 或 計算右邊緣百分比
// 或:在 Resize 事件中動態計算
| 場景 | 推薦佈局 | 理由 |
|---|---|---|
| 表單、屬性頁、對話框 | FormLayout | 精確控制標籤-輸入框對齊、按鈕固定底部、中間區域自適應 |
| 工具列、狀態列 | FormLayout | 左/中/右區域獨立控制 |
| 規則網格、表格狀介面 | GridLayout | 行列結構清晰,span/grab 機制直覺 |
| 動態增減元件 | GridLayout | 自動換行、重新排列較簡單 |
| 複雜重疊/置中需求 | FormLayout | SWT.CENTER 附著唯一支援 |
SWT.Resize 更新 FormData.width 並呼叫 layout()。new FormAttachment(50) 是指父容器 50% 處,而非元件中心。FormLayout 以「附著」概念提供像素級的佈局控制能力:
ControlListener 即時重算 FormData。掌握 FormAttachment 三種建構模式,即可駕馭最複雜的 SWT 介面佈局需求。