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

SWT 自定義 BorderLayout 佈局管理器完整實現

     編輯:Java 相關知識

背景動機

SWT 標準佈局管理器(FillLayout、RowLayout、GridLayout、FormLayout)功能強大,但缺乏類似 AWT/Swing BorderLayout 的五區域(北、南、東、西、中)佈局模型。本文實現一個完整的 BorderLayout 移植版,支援區域約束、元件動態調整、最佳尺寸計算等核心功能。

核心類別設計

BorderLayout 類別結構

public class BorderLayout extends Layout {
    // 五大區域常數
    public static final int NORTH = 0;
    public static final int SOUTH = 1;
    public static final int CENTER = 2;
    public static final int EAST = 3;
    public static final int WEST = 4;

    // 佈局約束資料類別
    public static class BorderData {
        public int region = CENTER;
        public BorderData() {}
        public BorderData(int region) { this.region = region; }
    }

    // 內部狀態
    private Control[] controls = new Control[5]; // 五區域控制項
    private Point[] sizes;                       // 各區域最佳尺寸
    private int width, height;                   // 整體最佳尺寸
}

關鍵方法實現

computeSize() - 計算最佳尺寸

@Override
protected Point computeSize(Composite composite, int wHint, int hHint, boolean flushCache) {
    if (sizes == null || flushCache) refreshSizes(composite.getChildren());
    int w = (wHint == SWT.DEFAULT) ? width : wHint;
    int h = (hHint == SWT.DEFAULT) ? height : hHint;
    return new Point(w, h);
}

layout() - 核心佈局演算法

@Override
protected void layout(Composite composite, boolean flushCache) {
    if (flushCache || sizes == null) refreshSizes(composite.getChildren());
    Rectangle area = composite.getClientArea();

    // 北區:頂部橫跨全寬
    if (controls[NORTH] != null) {
        controls[NORTH].setBounds(area.x, area.y, area.width, sizes[NORTH].y);
    }

    // 南區:底部橫跨全寬
    if (controls[SOUTH] != null) {
        controls[SOUTH].setBounds(
            area.x, 
            area.y + area.height - sizes[SOUTH].y, 
            area.width, 
            sizes[SOUTH].y
        );
    }

    // 西區:左側垂直佔據中間高度
    if (controls[WEST] != null) {
        controls[WEST].setBounds(
            area.x,
            area.y + sizes[NORTH].y,
            sizes[WEST].x,
            area.height - sizes[NORTH].y - sizes[SOUTH].y
        );
    }

    // 東區:右側垂直佔據中間高度
    if (controls[EAST] != null) {
        controls[EAST].setBounds(
            area.x + area.width - sizes[EAST].x,
            area.y + sizes[NORTH].y,
            sizes[EAST].x,
            area.height - sizes[NORTH].y - sizes[SOUTH].y
        );
    }

    // 中區:填滿剩餘空間
    if (controls[CENTER] != null) {
        controls[CENTER].setBounds(
            area.x + sizes[WEST].x,
            area.y + sizes[NORTH].y,
            area.width - sizes[WEST].x - sizes[EAST].x,
            area.height - sizes[NORTH].y - sizes[SOUTH].y
        );
    }
}

refreshSizes() - 尺寸快取刷新

private void refreshSizes(Control[] children) {
    // 重置控制項映射
    Arrays.fill(controls, null);
    
    // 解析佈局約束
    for (Control child : children) {
        Object data = child.getLayoutData();
        if (data instanceof BorderData) {
            BorderData bd = (BorderData) data;
            if (bd.region >= 0 && bd.region <= 4) {
                controls[bd.region] = child;
            }
        }
    }

    // 計算各區域最佳尺寸
    if (sizes == null) sizes = new Point[5];
    width = height = 0;
    
    for (int i = 0; i < 5; i++) {
        if (controls[i] != null) {
            sizes[i] = controls[i].computeSize(SWT.DEFAULT, SWT.DEFAULT, true);
        } else {
            sizes[i] = new Point(0, 0);
        }
    }

    // 整體寬度 = max(北寬, 西寬+中寬+東寬, 南寬)
    width = Math.max(width, sizes[NORTH].x);
    width = Math.max(width, sizes[WEST].x + sizes[CENTER].x + sizes[EAST].x);
    width = Math.max(width, sizes[SOUTH].x);

    // 整體高度 = 北高 + max(西高, 中高, 東高) + 南高
    height = sizes[NORTH].y + sizes[SOUTH].y 
           + Math.max(sizes[WEST].y, Math.max(sizes[CENTER].y, sizes[EAST].y));
}

使用範例

public class BorderLayoutDemo {
    public static void main(String[] args) {
        Display display = new Display();
        Shell shell = new Shell(display);
        shell.setText("BorderLayout 示範");
        shell.setLayout(new BorderLayout());

        // 建立五區域按鈕
        Button north = new Button(shell, SWT.PUSH);
        north.setText("北 - 頂部工具列");
        north.setLayoutData(new BorderLayout.BorderData(BorderLayout.NORTH));

        Button south = new Button(shell, SWT.PUSH);
        south.setText("南 - 狀態列");
        south.setLayoutData(new BorderLayout.BorderData(BorderLayout.SOUTH));

        Button west = new Button(shell, SWT.PUSH);
        west.setText("西 - 導航欄");
        west.setLayoutData(new BorderLayout.BorderData(BorderLayout.WEST));

        Button east = new Button(shell, SWT.PUSH);
        east.setText("東 - 側邊欄");
        east.setLayoutData(new BorderLayout.BorderData(BorderLayout.EAST));

        Text center = new Text(shell, SWT.MULTI | SWT.BORDER | SWT.V_SCROLL | SWT.H_SCROLL);
        center.setText("中 - 內容區域\n支援滾動\n自動填滿剩餘空間");
        center.setLayoutData(new BorderLayout.BorderData(BorderLayout.CENTER));

        shell.setSize(600, 400);
        shell.open();
        while (!shell.isDisposed()) {
            if (!display.readAndDispatch()) display.sleep();
        }
        display.dispose();
    }
}

進階特性與擴展

支援間距與邊距

public class BorderLayout extends Layout {
    private int hGap = 5, vGap = 5; // 水平/垂直間距
    private int marginTop = 5, marginBottom = 5, marginLeft = 5, marginRight = 5;

    public void setHgap(int hGap) { this.hGap = hGap; }
    public void setVgap(int vGap) { this.vGap = vGap; }
    public void setMargins(int top, int bottom, int left, int right) { ... }
    
    // layout() 中調整 bounds 計算時加入間距與邊距
}

動態區域顯示/隱藏

// 移除西區元件
Control west = controls[WEST];
if (west != null) {
    west.dispose(); // 或 west.setVisible(false)
    controls[WEST] = null;
    parent.layout(true); // 觸發重新佈局
}

總結

這個 BorderLayout 實現完整移植了 AWT/Swing 的經典五區域模型到 SWT 體系,核心優勢:

  • 零依賴:純 SWT API,無需額外庫。
  • 標準語義:行為與 AWT BorderLayout 高度一致,降低遷移成本。
  • 效能優化:尺寸快取機制避免重複計算。
  • 擴展性強:易於加入間距、邊距、動態區域等進階功能。

對於需要經典邊界佈局的 SWT/RCP 應用,這是一個開箱即用、生產級的解決方案。

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