StackLayout 是 SWT 中最簡單的「卡片式」佈局管理器。它將所有子元件疊放在同一位置,同一時間僅顯示一個(topControl)。適合向導嚮導、分頁介面、狀態切換(登入/主介面)、動畫過渡等場景。
topControl 可見,其餘隱藏(非銷毀)。topControl 呼叫 layout(),無重新計算開銷。StackLayout layout = new StackLayout();
parent.setLayout(layout);
// 切換顯示
layout.topControl = someControl;
parent.layout(true); // 必須呼叫以觸發重新佈局
// 獲取當前顯示
Control current = layout.topControl;
public class StackLayoutSample {
public static void main(String[] args) {
Display display = new Display();
Shell shell = new Shell(display);
shell.setText("StackLayout Demo");
StackLayout layout = new StackLayout();
shell.setLayout(layout);
final Button[] buttons = new Button[3];
for (int i = 0; i < buttons.length; i++) {
buttons[i] = new Button(shell, SWT.NONE);
buttons[i].setText("Button #" + i);
buttons[i].addSelectionListener(new SelectionListener() {
public void widgetSelected(SelectionEvent e) {
Button source = (Button) e.widget;
Button next = null;
for (int i = 0; i < buttons.length; i++) {
if (buttons[i] == source) {
next = (i == buttons.length - 1) ? buttons[0] : buttons[i + 1];
break;
}
}
layout.topControl = next;
shell.layout(); // 關鍵!
}
public void widgetDefaultSelected(SelectionEvent e) {}
});
}
layout.topControl = buttons[0]; // 初始顯示第一個
shell.setSize(200, 100);
shell.open();
while (!shell.isDisposed()) {
if (!display.readAndDispatch()) display.sleep();
}
display.dispose();
}
}
public class LoginMainSwitch {
private StackLayout layout;
private Composite loginPanel, mainPanel;
public void createUI(Shell shell) {
layout = new StackLayout();
shell.setLayout(layout);
// 登入面板
loginPanel = new Composite(shell, SWT.NONE);
loginPanel.setLayout(new GridLayout(2, false));
// ... 添加用戶名/密碼輸入、登入按鈕 ...
Button loginBtn = new Button(loginPanel, SWT.PUSH);
loginBtn.setText("Login");
loginBtn.addSelectionListener(e -> {
if (validate()) switchToMain();
});
// 主面板
mainPanel = new Composite(shell, SWT.NONE);
mainPanel.setLayout(new FillLayout());
// ... 主介面內容 ...
layout.topControl = loginPanel; // 預設顯示登入
}
private void switchToMain() {
layout.topControl = mainPanel;
loginPanel.getParent().layout(true);
}
private void switchToLogin() {
layout.topControl = loginPanel;
mainPanel.getParent().layout(true);
}
}
public class WizardStack {
private StackLayout layout;
private List pages = new ArrayList<>();
private int currentIndex = 0;
public void createWizard(Shell shell) {
layout = new StackLayout();
shell.setLayout(layout);
// 建立多個步驟面板
for (int i = 0; i < 3; i++) {
Composite page = new Composite(shell, SWT.NONE);
page.setLayout(new GridLayout());
// ... 每頁內容 ...
pages.add(page);
}
// 導航按鈕(放在 StackLayout 外層容器底部)
Composite navBar = new Composite(shell, SWT.NONE);
navBar.setLayoutData(new GridData(SWT.FILL, SWT.BOTTOM, true, false));
navBar.setLayout(new RowLayout());
Button back = new Button(navBar, SWT.PUSH);
back.setText("< Back");
back.addSelectionListener(e -> goPrevious());
Button next = new Button(navBar, SWT.PUSH);
next.setText("Next >");
next.addSelectionListener(e -> goNext());
Button finish = new Button(navBar, SWT.PUSH);
finish.setText("Finish");
finish.addSelectionListener(e -> finish());
layout.topControl = pages.get(0);
}
private void goNext() {
if (currentIndex < pages.size() - 1) {
layout.topControl = pages.get(++currentIndex);
shell.layout(true);
}
}
// ... goPrevious, finish ...
}
| 方案 | 原理 | 優點 | 缺點 | 適用場景 |
|---|---|---|---|---|
| StackLayout | 顯示/隱藏 | 極簡、極快、標準 API | 無動畫、無內建導航 | 向導、狀態切換、簡單分頁 |
| CTabFolder | 標籤頁 | 內建標籤、關閉、拖拽 | 較重、預設有標籤 UI | 標準分頁介面 |
| 手動 setVisible | 控件顯隱 | 完全控制 | 需自行管理佈局、佔位空間 | 特殊動畫、重疊效果 |
| ViewPart 切換 (RCP) | 工作台部件 | 生命週期管理、持久化 | 需 RCP 框架 | Eclipse RCP 應用 |
// 需結合 Alpha 值動畫,SWT 原生不直接支援
// 方案:兩層 Shell 疊加 + setAlpha() 漸變
// 或:使用 Canvas 繪製快照圖片動畫
// 頁面多時,僅在首次切換時建立
Control getPage(int index) {
Control page = pages.get(index);
if (page == null) {
page = createPage(index);
pages.set(index, page);
}
return page;
}
// 切換前保存當前頁面狀態(輸入值、滾動位置)
// 切換回來時恢復
// 可封裝為 IStackPage 接口:saveState()/restoreState()
parent.layout(true)。topControl,未顯示的控件自動隱藏。StackLayout 是「單顯示、多疊放」場景的標準解決方案:
topControl + layout()。當你需要「一次只看一個、快速切換」時,StackLayout 是首選。