SWT 以原生外觀著稱,但 IM 類應用常需獨特視覺風格。本文完整示範如何繼承 Composite 打造 MSN 風格下拉框(ComboSelector),涵蓋自繪邊框/圖標、內嵌 Text+Menu 組合、啟用/禁用雙態外觀、鍵盤/滑鼠事件、資料快取與動態載入,程式碼可直接作為可重用元件庫引用。
| 狀態 | 邊框色 | 背景色 |
|---|---|---|
| 啟用 | RGB(170,183,199) | RGB(254,254,254) |
| 禁用 | RGB(208,215,229) | RGB(238,241,249) |
下拉圖標:combo.png(需置於 classpath 根目錄)
public class ComboSelector extends Composite {
public ComboSelector(Composite parent) {
super(parent, SWT.FLAT); // 關鍵:避免原生凹陷邊框
...
}
}
addPaintListener(e -> {
GC gc = e.gc;
gc.setForeground(isEnabled() ? ENABLED_LINE_COLOR : DISABLED_LINE_COLOR);
gc.drawRectangle(0, 0, getSize().x - 1, getSize().y - 1);
// 圖標靠右 5px、垂直置中
gc.drawImage(COMBO_ICON,
getSize().x - COMBO_ICON.getBounds().width - 5,
(getSize().y - COMBO_ICON.getBounds().height) / 2);
});
addControlListener(new ControlAdapter() {
@Override public void controlResized(ControlEvent e) {
inputText.setBounds(1, 1,
getSize().x - COMBO_ICON.getBounds().width - 15,
getSize().y - 2);
}
});
public void setEnabled(boolean enabled) {
super.setEnabled(enabled);
setBackground(enabled ? ENABLED_BG : DISABLED_BG);
inputText.setEnabled(enabled);
redraw(); // 觸發 PaintListener 重繪邊框色
}
addMouseListener(new MouseAdapter() {
@Override public void mouseUp(MouseEvent e) {
if (isInComboButtonArea(e)) {
selectorMenu.setLocation(getScreenLocation().x + 3,
getScreenLocation().y + getSize().y + 23); // +23 修正標題列高度
selectorMenu.setVisible(true);
}
}
});
public void loadMenuItems(Object[] objects) {
dataSet.clear();
// 清除舊選單項
for (MenuItem item : selectorMenu.getItems()) {
item.removeSelectionListener(this);
item.dispose();
}
// 重建
for (Object obj : objects) {
dataSet.add(obj);
MenuItem item = new MenuItem(selectorMenu, SWT.PUSH);
item.setText(obj.toString()); // 需覆寫 POJO toString()
item.setData(obj); // 關鍵:存入原始物件
item.addSelectionListener(this);
}
}
@Override public void widgetSelected(SelectionEvent e) {
MenuItem item = (MenuItem) e.getSource();
selectedItem = item.getData();
inputText.setText(item.getText());
inputText.setSelection(0, item.getText().length());
selected(selectedItem); // 預留擴充點
}
ComboSelector selector = new ComboSelector(shell) {
@Override protected void commit() {
System.out.println("Enter 送出:" + ((Person)getSelectedItem()).getUserName());
}
@Override protected void selected(Object obj) {
System.out.println("選中密碼:" + ((Person)obj).getPassword());
}
};
selector.setBounds(114, 78, 200, 20);
selector.loadMenuItems(new Person[]{
new Person("play_station3@sina.com", "111111"),
new Person("rehte@hotmail.com", "222222"),
new Person("yitong.liu@bea.com", "password")
});
selector.select(1); // 預選第 2 項
swt.jar 與原生庫(swt-win32-*.dll 等)加入 classpath。