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

SWT/JFace Sash 與 SashForm 活動分割控件:手動拖曳與比例佈局管理

     編輯:Java 相關知識

Sash vs SashForm

SWT 提供兩種分割控件:

  • Sash (org.eclipse.swt.widgets.Sash):低階原生控件,僅提供可拖曳的分隔條,**開發者需自行監聽 Selection 事件計算並設定 bounds** 來調整左右/上下控件大小。彈性最高但使用繁瑣。
  • SashForm (org.eclipse.swt.custom.SashForm):高階封裝,內建佈局管理,**自動管理子控件大小與位置**,支援權重、最大化、巢狀分割。實務開發首選。

範例一:原生 Sash 手動拖曳邏輯

建立一個垂直 Sash,監聽 SWT.Selection,事件物件 Event 包含建議的新位置 e.x, e.y, e.width, e.height,直接套用至 Sash 自身 bounds。

package swt_jface.demo9;

import org.eclipse.swt.SWT;
import org.eclipse.swt.widgets.Display;
import org.eclipse.swt.widgets.Event;
import org.eclipse.swt.widgets.Listener;
import org.eclipse.swt.widgets.Sash;
import org.eclipse.swt.widgets.Shell;

public class SashExample {
    public static void main(String[] args) {
        Display display = new Display();
        Shell shell = new Shell(display);
        
        final Sash sash = new Sash(shell, SWT.BORDER | SWT.VERTICAL);
        sash.setBounds(10, 10, 15, 60); // 初始位置與大小 (寬15像素)
        
        sash.addListener(SWT.Selection, e -> {
            System.out.println("Selected. " + e.x + "," + e.y);
            // 關鍵:將事件建議的矩形套用回 Sash
            sash.setBounds(e.x, e.y, e.width, e.height);
            // 實務上這裡需同步調整左側/右側控件的 bounds
        });
        
        shell.open();
        sash.setFocus(); // 獲得焦點以接收鍵盤事件 (若支援)
        while (!shell.isDisposed()) {
            if (!display.readAndDispatch()) display.sleep();
        }
        display.dispose();
    }
}

注意:此範例僅展示 Sash 本身移動。實際應用中,必須在 Listener 中根據 e.x 重新計算並 setBounds 左側與右側的 Composite/Control,否則分割條移動但內容不跟隨。

範例二:SashForm 自動佈局與權重管理

展示水平 SashForm 包含三個面板 (Text, Text, 垂直 SashForm),設定權重 1:2:3。巢狀垂直 SashForm 示範雙擊 Label 最大化/還原功能。

package swt_jface.demo9;

import org.eclipse.swt.SWT;
import org.eclipse.swt.custom.SashForm;
import org.eclipse.swt.events.ControlEvent;
import org.eclipse.swt.events.ControlListener;
import org.eclipse.swt.events.MouseEvent;
import org.eclipse.swt.events.MouseListener;
import org.eclipse.swt.layout.FillLayout;
import org.eclipse.swt.widgets.Display;
import org.eclipse.swt.widgets.Label;
import org.eclipse.swt.widgets.Shell;
import org.eclipse.swt.widgets.Text;

public class SashFormExample {
    Display display = new Display();
    Shell shell = new Shell(display);
    SashForm sashForm, sashForm2;

    public SashFormExample() {
        shell.setLayout(new FillLayout());

        // 主水平分割
        sashForm = new SashForm(shell, SWT.HORIZONTAL);
        Text text1 = new Text(sashForm, SWT.CENTER | SWT.BORDER);
        text1.setText("Text in pane #1");
        Text text2 = new Text(sashForm, SWT.CENTER | SWT.BORDER);
        text2.setText("Text in pane #2");

        // 巢狀垂直分割 (放在第3個位置)
        sashForm2 = new SashForm(sashForm, SWT.VERTICAL);
        final Label labelA = new Label(sashForm2, SWT.BORDER | SWT.CENTER);
        labelA.setText("Label in pane A");
        final Label labelB = new Label(sashForm2, SWT.BORDER | SWT.CENTER);
        labelB.setText("Label in pane B");

        // 監聽尺寸變化 (除錯用)
        text1.addControlListener(new ControlListener() {
            public void controlMoved(ControlEvent e) {}
            public void controlResized(ControlEvent e) {
                System.out.println("Resized. Weights: " + java.util.Arrays.toString(sashForm.getWeights()));
            }
        });

        // 設定初始權重:Pane1:Pane2:Pane3 = 1:2:3
        sashForm.setWeights(new int[]{1, 2, 3});

        // 雙擊 Label 最大化/還原該面板
        labelA.addMouseListener(new MouseListener() {
            public void mouseDoubleClick(MouseEvent e) {
                if (sashForm2.getMaximizedControl() == labelA)
                    sashForm2.setMaximizedControl(null); // 還原
                else
                    sashForm2.setMaximizedControl(labelA); // 最大化佔滿 sashForm2
            }
            public void mouseDown(MouseEvent e) {}
            public void mouseUp(MouseEvent e) {}
        });

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

    public static void main(String[] args) {
        new SashFormExample();
    }
}

SashForm 核心 API 詳解

1. 建構子與方向

new SashForm(parent, SWT.HORIZONTAL) // 左右分割,Sash 垂直
new SashForm(parent, SWT.VERTICAL)   // 上下分割,Sash 水平

2. 權重

  • setWeights(int[]):設定各面板相對寬度/高度比例。總和不需為 100,如 {1, 2, 3} 表示 1/6, 2/6, 3/6。
  • getWeights():取得目前比例 (使用者拖曳後會更新)。
  • 動態調整:sashForm.setWeights(newWeights); sashForm.layout();。

3. 最大化控件

  • setMaximizedControl(Control):指定控件佔滿整個 SashForm 空間,其他控件隱藏。Sash 暫時消失。
  • getMaximizedControl():取得目前最大化控件,null 代表正常模式。
  • 常用於「雙擊標題欄最大化」或「工具按鈕切換全螢幕編輯」。

4. 佈局行為

SashForm 實作 Layout 介面。父容器若用 FillLayout,SashForm 會填滿父容器。子控件無需設定 LayoutData,SashForm 依權重自動計算 bounds。

進階技巧:持久化使用者偏好

記住使用者調整的分割比例,下次啟動還原:

// 關閉視窗前儲存
prefs.putInt("sashWeight1", sashForm.getWeights()[0]);
prefs.putInt("sashWeight2", sashForm.getWeights()[1]);

// 啟動時還原
int[] weights = { prefs.getInt("sashWeight1", 1), prefs.getInt("sashWeight2", 2) };
sashForm.setWeights(weights);

常見問題與避坑

  1. SashForm 不顯示分割條:確認 Style 正確 (SWT.HORIZONTAL/VERTICAL) 且子控件數量 ≥ 2。
  2. 巢狀 SashForm 權重失效:內層 SashForm 的權重僅影響其內部空間分配,外層權重決定內層整體佔比。
  3. 最大化後無法還原:需提供 UI 觸發點 (如工具列按鈕、雙擊事件) 呼叫 setMaximizedControl(null)。
  4. 最小尺寸限制:SashForm 允許拖曳至寬/高為 0。若需最小尺寸,可監聽 ControlListener 或自訂 SashForm (繼承覆寫 computeSize),但較複雜。通常靠 UI 設計避免 (如 ToolBar 最小寬度)。

總結

SashForm 是構建可調整大小分割介面的標準選擇。它封裝了繁瑣的幾何計算,提供權重、最大化、巢狀分割等豐富功能。僅在需要極度客製化分割條外觀 (如自訂圖形、顏色、吸附行為) 時,才考慮直接使用原生 Sash 並自行管理佈局邏輯。

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