選單列、工具列、酷工具列是桌面應用的核心導航元件。SWT 提供 Menu、ToolBar、CoolBar 三大類別,JFace 進一步封裝 MenuManager、ToolBarManager、CoolBarManager 簡化動作管理。本文透過三個完整範例,詳細解析各元件的建立、事件處理、圖示設定、快捷鍵、下拉選單、狀態持久化等實務技巧。
Menu menuBar = new Menu(shell, SWT.BAR); // 選單列
shell.setMenuBar(menuBar);
MenuItem fileItem = new MenuItem(menuBar, SWT.CASCADE);
fileItem.setText("&File");
Menu fileMenu = new Menu(shell, SWT.DROP_DOWN);
fileItem.setMenu(fileMenu);
MenuItem newItem = new MenuItem(fileMenu, SWT.PUSH);
newItem.setText("&New\tCtrl+N");
newItem.setAccelerator(SWT.CTRL | 'N');
newItem.addListener(SWT.Selection, e -> System.out.println("New"));
| Style | 用途 | 範例 |
|---|---|---|
SWT.CASCADE | 包含子選單的項目 | File、Edit 等主選單 |
SWT.PUSH | 一般命令項目 | New、Open、Save |
SWT.CHECK | 可切換狀態(打勾) | 顯示行號、自動換行 |
SWT.RADIO | 單選群組(同組互斥) | 語言選擇、主題切換 |
SWT.SEPARATOR | 分隔線 | 群組分隔 |
Image icon = new Image(display, "icons/new.gif");
newItem.setImage(icon);
newItem.setAccelerator(SWT.CTRL | 'N'); // 真正觸發快捷鍵
newItem.setText("&New\tCtrl+N"); // 顯示用快捷鍵提示
setAccelerator 才是真正註冊鍵盤快捷鍵;\t 後的文字僅為顯示提示。
ToolItem dropDown = new ToolItem(toolBar, SWT.DROP_DOWN);
dropDown.setText("Options");
Menu popup = new Menu(shell, SWT.POP_UP);
new MenuItem(popup, SWT.PUSH).setText("Item 1");
new MenuItem(popup, SWT.PUSH).setText("Item 2");
dropDown.addListener(SWT.Selection, e -> {
if (e.detail == SWT.ARROW) { // 僅點擊箭頭區域
Rectangle bounds = dropDown.getBounds();
Point pt = toolBar.toDisplay(bounds.x, bounds.y + bounds.height);
popup.setLocation(pt);
popup.setVisible(true);
}
});
ToolBar toolBar = new ToolBar(shell, SWT.FLAT | SWT.WRAP | SWT.RIGHT);
toolBar.pack(); // 依元件建議尺寸調整
shell.addListener(SWT.Resize, e -> {
Rectangle area = shell.getClientArea();
toolBar.setSize(toolBar.computeSize(area.width, SWT.DEFAULT));
});
SWT.FLAT:扁平風格(現代外觀)SWT.WRAP:空間不足時自動換行SWT.RIGHT:靠右對齊// 一般按鈕
ToolItem push = new ToolItem(toolBar, SWT.PUSH);
push.setText("Push"); push.setImage(icon);
// 核取方塊/單選按鈕
ToolItem check = new ToolItem(toolBar, SWT.CHECK);
ToolItem radio1 = new ToolItem(toolBar, SWT.RADIO);
ToolItem radio2 = new ToolItem(toolBar, SWT.RADIO); // 同組自動互斥
// 分隔器可嵌入控制項
ToolItem sep = new ToolItem(toolBar, SWT.SEPARATOR);
Text text = new Text(toolBar, SWT.BORDER | SWT.SINGLE);
text.pack();
sep.setWidth(text.getBounds().width);
sep.setControl(text); // 文字框嵌入工具列
Listener listener = e -> {
ToolItem item = (ToolItem) e.widget;
System.out.println(item.getText() + " selected");
if ((item.getStyle() & SWT.CHECK) != 0 || (item.getStyle() & SWT.RADIO) != 0)
System.out.println("State: " + item.getSelection());
};
push.addListener(SWT.Selection, listener);
check.addListener(SWT.Selection, listener);
radio1.addListener(SWT.Selection, listener);
radio2.addListener(SWT.Selection, listener);
CoolItemCoolBar coolBar = new CoolBar(shell, SWT.NONE);
coolBar.setLayoutData(new GridData(GridData.FILL_HORIZONTAL));
// 文字輸入項
CoolItem textItem = new CoolItem(coolBar, SWT.NONE);
Text text = new Text(coolBar, SWT.BORDER | SWT.DROP_DOWN);
text.setText("TEXT");
text.pack();
textItem.setControl(text);
textItem.setSize(textItem.computeSize(text.getSize().x, text.getSize().y));
// 標籤項
CoolItem labelItem = new CoolItem(coolBar, SWT.NONE);
Label label = new Label(coolBar, SWT.NONE);
label.setText("LABEL");
label.pack();
labelItem.setControl(label);
labelItem.setSize(labelItem.computeSize(label.getSize().x, label.getSize().y));
// 複合控制項項(按鈕群組)
CoolItem btnItem = new CoolItem(coolBar, SWT.NONE | SWT.DROP_DOWN);
Composite comp = new Composite(coolBar, SWT.NONE);
comp.setLayout(new GridLayout(2, true));
new Button(comp, SWT.PUSH).setText("Button 1");
new Button(comp, SWT.PUSH).setText("Button 2");
comp.pack();
btnItem.setControl(comp);
btnItem.setSize(btnItem.computeSize(comp.getSize().x, comp.getSize().y));
// 儲存
void saveState(CoolBar bar, File file) throws IOException {
DataOutputStream out = new DataOutputStream(new FileOutputStream(file));
try {
int[] order = bar.getItemOrder();
out.writeInt(order.length);
for (int i : order) out.writeInt(i);
int[] wraps = bar.getWrapIndices();
out.writeInt(wraps.length);
for (int i : wraps) out.writeInt(i);
Point[] sizes = bar.getItemSizes();
out.writeInt(sizes.length);
for (Point p : sizes) { out.writeInt(p.x); out.writeInt(p.y); }
} finally { out.close(); }
}
// 載入
void setState(CoolBar bar, File file) throws IOException {
DataInputStream in = new DataInputStream(new FileInputStream(file));
try {
int[] order = new int[in.readInt()];
for (int i = 0; i < order.length; i++) order[i] = in.readInt();
int[] wraps = new int[in.readInt()];
for (int i = 0; i < wraps.length; i++) wraps[i] = in.readInt();
Point[] sizes = new Point[in.readInt()];
for (int i = 0; i < sizes.length; i++) sizes[i] = new Point(in.readInt(), in.readInt());
bar.setItemLayout(order, wraps, sizes);
} finally { in.close(); }
}
// 視窗關閉時自動儲存
shell.addListener(SWT.Close, e -> {
try { saveState(coolBar, new File("coolbar.state")); }
catch (IOException ex) { ex.printStackTrace(); }
});
實際專案建議使用 JFace 的 MenuManager、ToolBarManager、CoolBarManager 搭配 Action / IAction:
IContributionItem 動態貢獻、Expression 可見性控制Menu、ToolBar、CoolBar 是 SWT 應用導航的三大支柱。掌握其核心 API、事件模型、佈局特性與持久化技巧,並善用 JFace 封裝提升可維護性,即可打造出專業級的桌面應用介面。