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

Java SWT 自定義組件實戰:打造 MSN 風格下拉選單

     編輯:Java 相關知識

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 根目錄)

核心實作要點

1. 繼承 Composite + FLAT 風格

public class ComboSelector extends Composite {
    public ComboSelector(Composite parent) {
        super(parent, SWT.FLAT);  // 關鍵:避免原生凹陷邊框
        ...
    }
}

2. PaintListener 自繪邊框與圖標

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);
});

3. ControlListener 動態調整內嵌 Text 位置

addControlListener(new ControlAdapter() {
    @Override public void controlResized(ControlEvent e) {
        inputText.setBounds(1, 1,
            getSize().x - COMBO_ICON.getBounds().width - 15,
            getSize().y - 2);
    }
});

4. 重寫 setEnabled 雙態同步

public void setEnabled(boolean enabled) {
    super.setEnabled(enabled);
    setBackground(enabled ? ENABLED_BG : DISABLED_BG);
    inputText.setEnabled(enabled);
    redraw();  // 觸發 PaintListener 重繪邊框色
}

5. 滑鼠點擊下拉區域彈出 Menu

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);
        }
    }
});

6. 資料綁定:Vector<Object> + MenuItem.setData()

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);
    }
}

7. 選擇事件回呼

@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。
  • Eclipse 開發可安裝 WindowBuilder/SWT Designer 視覺化拖曳。
  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved