複合控件將多個子控件封裝於單一 ActiveX 介面,適合建立可重用的 UI 模組。本文以 ATL 7.0/8.0 為例,逐步示範建立含「列表檢視 + 進度條」的複合控件,並實作連接點事件回呼給容器(如 VB、C#、網頁)。
AtlSample),預設選項完成。AtlComp。IDD_ATLCOMP,拖入 List Control (IDC_LIST1) 與 Progress Control (IDC_PROGRESS1)。AtlComp.h 引入 #include <CommCtrl.h>。HIMAGELIST m_hImlIcons; HWND m_hListCtrl;LRESULT OnInitDialog(UINT, WPARAM, LPARAM, BOOL&)
{
// 進度條顏色
SendDlgItemMessage(IDC_PROGRESS1, PBM_SETBARCOLOR, 0, (LPARAM)RGB(0,128,0));
SendDlgItemMessage(IDC_PROGRESS1, PBM_SETPOS, 0, 0);
// 列表檢視初始化
m_hListCtrl = GetDlgItem(IDC_LIST1);
m_hImlIcons = ImageList_Create(16, 16, ILC_MASK | ILC_COLOR32, 2, 0);
HICON hIcon = LoadIcon(_Module.m_hInstResource, MAKEINTRESOURCE(IDI_ICON_LIST));
ImageList_AddIcon(m_hImlIcons, hIcon);
ListView_SetImageList(m_hListCtrl, m_hImlIcons, LVSIL_SMALL);
ListView_SetExtendedListViewStyle(m_hListCtrl, LVS_EX_FULLROWSELECT);
// 欄位
LV_COLUMN lvCol = { LVCF_TEXT | LVCF_WIDTH, LVCFMT_LEFT };
lvCol.cx = 200; lvCol.pszText = "檔案名稱"; ListView_InsertColumn(m_hListCtrl, 0, &lvCol);
lvCol.cx = 80; lvCol.pszText = "檔案大小"; ListView_InsertColumn(m_hListCtrl, 1, &lvCol);
return 0;
}
LRESULT OnDestroy(UINT, WPARAM, LPARAM, BOOL&)
{
ImageList_Destroy(m_hImlIcons);
return 0;
}
清空列表、插入示範項目、更新進度條 50%。
STDMETHODIMP AtlComp::Atl()
{
ListView_DeleteAllItems(m_hListCtrl);
LVITEM lvItem = { LVIF_TEXT | LVIF_IMAGE, 0, 0, 0, 0, L"我愛VC.C++", 0 };
ListView_InsertItem(m_hListCtrl, &lvItem);
ListView_SetItemText(m_hListCtrl, 0, 1, L"1024");
SendDlgItemMessage(IDC_PROGRESS1, PBM_SETPOS, 50, 0);
return S_OK;
}
AtlEven,參數 [in] long lState, [in] char* lpszInfo。Atl() 方法首尾觸發事件:Fire_AtlEven(0, "方法開始"); … Fire_AtlEven(1, "方法結束");AtlComp 控件(ID: IDC_ATLCOMP1)。DECLARE_EVENTSINK_MAP()。BEGIN_EVENTSINK_MAP(CTestAtlDlg, CDialog)
ON_EVENT(CTestAtlDlg, IDC_ATLCOMP1, 1, OnAtlEvent, VTS_I4 VTS_BSTR)
END_EVENTSINK_MAP()
void CTestAtlDlg::OnAtlEvent(long state, LPCTSTR buf)
{
// state: 0=開始, 1=結束; buf: 文字描述
TRACE("AtlEven: %d - %s\n", state, buf);
}
| 項目 | 說明 |
|---|---|
| 複合控件基類 | CComControl<T> + IPersistStreamInitImpl + IOleControlImpl 等 |
| 子視窗建立時機 | OnCreate 或 WM_INITDIALOG,勿用 WS_VISIBLE,由容器控制顯示 |
| 連接點觸發 | Fire_<EventName> 由 ATL 產生,自動遍歷所有訂閱端 |
| 測試容器事件接收 | MFC 使用 EVENTSINK_MAP,.NET 直接 += 事件處理器 |
此範例展示 ATL 複合控件的完整生命週期,可直接擴充為生產級 UI 元件庫。