首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> Java 程式設計 >> Java 相關知識

SWT 布局管理器完全指南:FillLayout、RowLayout、GridLayout 與自定義布局實戰

     編輯:Java 相關知識

SWT 採用布局管理器機制實現跨平台 GUI 的自適應定位,避免絕對座標在不同解析度、字型、DPI 下的失效。本文系統介紹四大核心布局管理器的特性、參數配置與實戰代碼,並示範如何繼承 Layout 抽象類開發自定義布局。

布局管理器核心概念

  • 托管定位:由 LayoutManager 計算子組件位置、大小,父組件大小變化時自動重排。
  • LayoutData:部分布局需為每個子組件指定專屬佈局數據(如 GridData),控制對齊、跨格、邊距等細節。
  • 啟用流程:建立 Layout 實例 → parent.setLayout(layout) → 為子組件設定 LayoutData(可選) → 父組件調整大小時自動觸發佈局。

FillLayout:等分填充佈局

最簡單佈局,子組件等寬/等高單行或單列排列。適用於工具列、狀態列或單一組件填滿父容器。

風格參數(建構子傳入)

常數說明
SWT.HORIZONTAL水平排列(預設)
SWT.VERTICAL垂直排列

關鍵屬性

  • marginWidth、marginHeight:左右/上下邊距(像素)
  • spacing:組件間距

實戰範例

FillLayout fillLayout = new FillLayout(SWT.HORIZONTAL);
fillLayout.marginHeight = 25;
fillLayout.marginWidth = 25;
fillLayout.spacing = 10;
shell.setLayout(fillLayout);

new Button(shell, SWT.PUSH).setText("button1");
new Button(shell, SWT.PUSH).setText("button number 2");
new Button(shell, SWT.PUSH).setText("3");
shell.pack(); shell.open();

FillLayout 實例效果

圖 1 FillLayout 布局實例

RowLayout:流式排列佈局

類似 HTML 流式佈局,支援換行、組件保持原尺寸、邊距與間距獨立設定。

常用屬性

屬性說明
wrap是否自動換行(true/false)
pack組件是否保持原有大小(true/false)
justify是否根據父組件寬度調整組件寬度
marginLeft/Top/Right/Bottom四邊邊距
spacing組件間距

RowData 控制單一組件尺寸

button.setLayoutData(new RowData(60, 60)); // 固定 60x60 像素

實戰範例

RowLayout rowLayout = new RowLayout();
rowLayout.pack = true;
rowLayout.wrap = true;
rowLayout.justify = true;
rowLayout.marginLeft = 30;
rowLayout.marginTop = 30;
shell.setLayout(rowLayout);

Text t = new Text(shell, SWT.SINGLE | SWT.BORDER);
Button b = new Button(shell, SWT.BORDER); b.setText("OK");
Button b1 = new Button(shell, SWT.BORDER); b1.setText("Cancel");
b1.setLayoutData(new RowData(60, 60));

RowLayout 實例效果

圖 2 RowLayout 布局實例

GridLayout:網格式強力佈局(最推薦)

將父組件劃分為行列網格,子組件按加入順序依序佔據單元格,支援跨行跨列、多種對齊、邊距、間距與動態搶佔空間。

GridLayout 核心屬性

屬性說明
numColumns列數(必設)
makeColumnsEqualWidth所有列等寬(true/false)
marginLeft/Top/Right/Bottom四邊邊距
horizontalSpacing水平間距
verticalSpacing垂直間距

GridData:單元格級精細控制

每個子組件需獨立 GridData 實例(不可共用)。關鍵屬性:

屬性說明
horizontalAlignment水平對齊:BEGINNING, CENTER, END, FILL
verticalAlignment垂直對齊:同上
horizontalIndent水平縮進(需配合 BEGINNING)
horizontalSpan跨列數
verticalSpan跨行數
grabExcessHorizontalSpace父寬度變化時是否水平搶佔空間
grabExcessVerticalSpace父高度變化時是否垂直搶佔空間
widthHint, heightHint建議寬/高(像素)

複雜表單實戰:狗展報名表單

GridLayout gridLayout = new GridLayout();
gridLayout.numColumns = 3;
shell.setLayout(gridLayout);

// Dog Name: 標籤 + 輸入框跨兩列
new Label(shell, SWT.NONE).setText("Dog's Name:");
dogName = new Text(shell, SWT.SINGLE | SWT.BORDER);
GridData gd = new GridData(GridData.HORIZONTAL_ALIGN_FILL);
gd.horizontalSpan = 2;
dogName.setLayoutData(gd);

// Breed: 下拉框填滿
new Label(shell, SWT.NONE).setText("Breed:");
dogBreed = new Combo(shell, SWT.NONE);
dogBreed.setItems(new String[]{"Collie","Pitbull","Poodle","Scottie"});
dogBreed.setLayoutData(new GridData(GridData.HORIZONTAL_ALIGN_FILL));

// Photo: Canvas 佔 3 行、雙向填滿
new Label(shell, SWT.NONE).setText("Photo:");
dogPhoto = new Canvas(shell, SWT.BORDER);
gd = new GridData(GridData.FILL_BOTH);
gd.widthHint = 80; gd.heightHint = 80;
gd.verticalSpan = 3;
dogPhoto.setLayoutData(gd);

// Categories: List 佔 4 行、雙向填滿
categories = new List(shell, SWT.MULTI | SWT.BORDER | SWT.V_SCROLL);
categories.setItems(new String[]{"Best of Breed", ...});
gd = new GridData(GridData.HORIZONTAL_ALIGN_FILL | GridData.VERTICAL_ALIGN_FILL);
gd.verticalSpan = 4;
gd.heightHint = categories.getItemHeight() * 12;
categories.setLayoutData(gd);

// Buttons with indent
Button browse = new Button(shell, SWT.PUSH); browse.setText("Browse...");
gd = new GridData(GridData.HORIZONTAL_ALIGN_FILL); gd.horizontalIndent = 5;
browse.setLayoutData(gd);

// Owner Info Group (巢狀 GridLayout)
Group ownerInfo = new Group(shell, SWT.NONE);
ownerInfo.setText("Owner Info");
GridLayout gl = new GridLayout(); gl.numColumns = 2;
ownerInfo.setLayout(gl);
gd = new GridData(GridData.HORIZONTAL_ALIGN_FILL); gd.horizontalSpan = 2;
ownerInfo.setLayoutData(gd);
// ... 群組內部元件略 ...

// Enter 按鈕靠右、跨 3 列
Button enter = new Button(shell, SWT.PUSH); enter.setText("Enter");
gd = new GridData(GridData.HORIZONTAL_ALIGN_END); gd.horizontalSpan = 3;
enter.setLayoutData(gd);

GridLayout 複雜表單效果

圖 5 GridLayout 布局實例

鐵律:每個子組件必須擁有獨立 GridData 實例,即使屬性相同也需 new 多個。

自定義布局:繼承 Layout 抽象類

當內建布局無法滿足特殊需求(如固定列寬、特殊對齊邏輯),可自行實作 Layout 子類。

必須實作的兩個抽象方法

  • computeSize(Composite, wHint, hHint, flushCache):計算所有子組件所需總寬高,回傳 Point。
  • layout(Composite, flushCache):計算並設定每個子組件的具體位置與大小(setBounds)。

範例:ColumnLayout(單列、等寬、固定間距)

public class ColumnLayout extends Layout {
    public static final int MARGIN = 4;
    public static final int SPACING = 2;
    Point[] sizes;
    int maxWidth, totalHeight;

    protected Point computeSize(Composite c, int wHint, int hHint, boolean flushCache) {
        Control[] children = c.getChildren();
        if (flushCache || sizes == null || sizes.length != children.length) initialize(children);
        int w = (wHint == SWT.DEFAULT) ? maxWidth : wHint;
        int h = (hHint == SWT.DEFAULT) ? totalHeight : hHint;
        return new Point(w + 2*MARGIN, h + 2*MARGIN);
    }

    protected void layout(Composite c, boolean flushCache) {
        Control[] children = c.getChildren();
        if (flushCache || sizes == null || sizes.length != children.length) initialize(children);
        Rectangle area = c.getClientArea();
        int x = MARGIN, y = MARGIN;
        int width = Math.max(area.width - 2*MARGIN, maxWidth);
        for (int i=0; i

測試自定義布局

shell.setLayout(new ColumnLayout());
new Button(shell, SWT.PUSH).setText("B1");
new Button(shell, SWT.PUSH).setText("Very Wide Button 2");
Button b3 = new Button(shell, SWT.PUSH); b3.setText("Button 3");
new Text(shell, SWT.NONE).setText("text");

// 動態改變按鈕文字寬度並觸發重排
Button grow = new Button(shell, SWT.PUSH); grow.setText("Grow Button 3");
grow.addSelectionListener(new SelectionAdapter() {
    public void widgetSelected(SelectionEvent e) {
        b3.setText("Extreemely Wide Button 3");
        shell.layout(); shell.pack();
    }
});

自定義布局效果

圖 6 自己定義布局(原始大小 / 寬度改變後)

總結與建議

  • FillLayout:簡單等分場景。
  • RowLayout:流式、需自動換行的工具列/表單。
  • GridLayout:最通用、最強大,複雜表單、對話框首選,掌握 GridData 細節可應對 90%+ 佈局需求。
  • FormLayout:極精細相對定位(本文未詳述,有興趣可自行研究)。
  • 自定義 Layout:特殊業務邏輯佈局時介入,核心在於正確實作 computeSize 與 layout。

熟練運用這幾種佈局方式,並理解 LayoutData 的角色,是開發健壯、跨平台 SWT 介面的關鍵基礎。

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved