效果图:
头文件定义(CSWCheckComboBox.h):
#pragma once
class CSWCheckComboBox : public CComboBox
{
DECLARE_DYNAMIC(CSWCheckComboBox)
// 成员私有结构定义
// 构造/析构函数
public:
CSWCheckComboBox();
virtual ~CSWCheckComboBox();
// 私有成员变量
private:
// 私有成员函数
private:
void CommonConstruct(); // 初始化
// 受保护成员变量
protected:
CListBox* m_pListBox;
WNDPROC m_pOldWndProc;
// 受保护成员函数
protected:
CString UpdateCheckedText(BOOL bReupdate = TRUE);
LRESULT OnListBoxWindowProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam);
// 虚函数
protected:
virtual BOOL Create(DWORD dwStyle, const RECT& rect, CWnd* pParentWnd, UINT nID);
virtual void DrawItem(LPDRAWITEMSTRUCT lpDrawItemStruct);
// 消息函数
protected:
DECLARE_MESSAGE_MAP()
afx_msg LRESULT OnCtlColorListBox(WPARAM wParam, LPARAM lParam);
afx_msg LRESULT OnGetText(WPARAM wParam, LPARAM lParam);
afx_msg LRESULT OnGetTextLength(WPARAM wParam, LPARAM lParam);
// 共有成员变量
public:
int SetCheck(int nIndex, int nCheck, BOOL bRepaint = TRUE);
BOOL GetCheck(int nIndex);
void CheckAll(BOOL bCheck = TRUE);
// 共有成员函数
public:
// 静态成员变量
public:
// 静态成员函数
public:
static LRESULT ListBoxWindowProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam);
};
源码实现(CSWCheckComboBox.cpp):
#include "stdafx.h"
#include "CSWCheckComboBox.h"
CSWCheckComboBox::CSWCheckComboBox()
{
CommonConstruct();
}
CSWCheckComboBox::~CSWCheckComboBox()
{
}
IMPLEMENT_DYNAMIC(CSWCheckComboBox, CComboBox)
BEGIN_MESSAGE_MAP(CSWCheckComboBox, CComboBox)
//{{AFX_MSG_MAP(CSWCheckComboBox)
ON_MESSAGE(WM_CTLCOLORLISTBOX, OnCtlColorListBox)
ON_MESSAGE(WM_GETTEXT, OnGetText)
ON_MESSAGE(WM_GETTEXTLENGTH, OnGetTextLength)
//}}AFX_MSG_MAP
END_MESSAGE_MAP()
void CSWCheckComboBox::CommonConstruct()
{
m_pListBox = NULL;
m_pOldWndProc = NULL;
}
LRESULT CSWCheckComboBox::ListBoxWindowProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
{
CSWCheckComboBox* pThis = (CSWCheckComboBox*)GetProp(hWnd, _T("CComboBoxHelper"));
if (pThis == NULL)
return S_OK;
return pThis->OnListBoxWindowProc(hWnd, message, wParam, lParam);
}
LRESULT CSWCheckComboBox::OnListBoxWindowProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
{
TRACE(_T("%d...%d\n"), message, GetTickCount());
switch (message)
{
case LB_GETCURSEL:
return -1;
case WM_KEYDOWN:
{
if (wParam == VK_DOWN || wParam == VK_UP)
{
int nIndex = CallWindowProc(m_pOldWndProc, hWnd, LB_GETCURSEL, wParam, lParam);
if (wParam == VK_DOWN)
++nIndex;
else
--nIndex;
if (nIndex >= GetCount() || nIndex < 0)
return S_OK;
m_pListBox->SetCurSel(nIndex);
return S_OK;
}
}
break;
case WM_CHAR:
{
if (wParam == VK_SPACE)
{
int nIndex = CallWindowProc(m_pOldWndProc, hWnd, LB_GETCURSEL, wParam, lParam);
CRect rcItem;
m_pListBox->GetItemRect(nIndex, rcItem);
m_pListBox->InvalidateRect(rcItem, FALSE);
SetCheck(nIndex, !GetCheck(nIndex));
return S_OK;
}
break;
}
case WM_LBUTTONDOWN:
{
CRect rcClient;
m_pListBox->GetClientRect(rcClient);
CPoint point;
point.x = LOWORD(lParam);
point.y = HIWORD(lParam);
if (rcClient.PtInRect(point))
{
int nItemHeight = GetItemHeight(0);
int nTopIndex = GetTopIndex();
int nIndex = nTopIndex + point.y / nItemHeight;
CRect rcItem;
m_pListBox->GetItemRect(nIndex, rcItem);
if (PtInRect(rcItem, point))
{
m_pListBox->InvalidateRect(rcItem, FALSE);
SetCheck(nIndex, !GetCheck(nIndex));
}
}
break;
}
case WM_LBUTTONUP:
return S_OK;
case WM_MOUSEMOVE:
TRACE("%s::WM_MOUSEMOVE(%d)\n", GetRuntimeClass()->m_lpszClassName, GetTickCount());
CRect rcClient;
m_pListBox->GetClientRect(rcClient);
CPoint point;
point.x = LOWORD(lParam);
point.y = HIWORD(lParam);
if (!rcClient.PtInRect(point))
return E_FAIL;
break;
}
return CallWindowProc(m_pOldWndProc, hWnd, message, wParam, lParam);
}
BOOL CSWCheckComboBox::Create(DWORD dwStyle, const RECT& rect, CWnd* pParentWnd, UINT nID)
{
// 动态创建的控件才会到这里来,否则需要手动修改这些属性
dwStyle &= ~0x0F;
dwStyle |= CBS_DROPDOWNLIST;
dwStyle |= CBS_OWNERDRAWFIXED;
dwStyle |= CBS_HASSTRINGS;
return CComboBox::Create(dwStyle, rect, pParentWnd, nID);
}
LRESULT CSWCheckComboBox::OnCtlColorListBox(WPARAM wParam, LPARAM lParam)
{
if (m_pListBox == NULL)
{
HWND hWnd = (HWND)lParam;
if (hWnd != 0 && hWnd != m_hWnd)
{
if (!SetProp(hWnd, _T("CComboBoxHelper"), (HANDLE)this))
return E_FAIL;
m_pOldWndProc = (WNDPROC)GetWindowLong(hWnd, GWL_WNDPROC);
SetWindowLong(hWnd, GWL_WNDPROC, (LONG)CSWCheckComboBox::ListBoxWindowProc);
m_pListBox = (CListBox*)CWnd::FromHandle(hWnd);
}
}
return DefWindowProc(WM_CTLCOLORLISTBOX, wParam, lParam);
}
void CSWCheckComboBox::DrawItem(LPDRAWITEMSTRUCT lpDrawItemStruct)
{
TRACE("%s::DoPaint(%d)\n", this->GetRuntimeClass()->m_lpszClassName, GetTickCount());
CDC dc;
if (!dc.Attach(lpDrawItemStruct->hDC))
return;
CRect rcBitmap = lpDrawItemStruct->rcItem;
CRect rcText = lpDrawItemStruct->rcItem;
CString strText;
int nCheck = 0;
if ((LONG)lpDrawItemStruct->itemID < 0)
{
CString strSelText = UpdateCheckedText(FALSE);
strText = strSelText;
nCheck = 0;
}
else
{
GetLBText(lpDrawItemStruct->itemID, strText);
nCheck = 1 + (GetItemData(lpDrawItemStruct->itemID) != 0);
TEXTMETRIC metrics;
dc.GetTextMetrics(&metrics);
rcBitmap.left = 0;
rcBitmap.right = rcBitmap.left + metrics.tmHeight + metrics.tmExternalLeading + 6;
rcBitmap.top += 1;
rcBitmap.bottom -= 1;
rcText.left = rcBitmap.right;
}
if (nCheck > 0)
{
dc.SetBkColor(GetSysColor(COLOR_WINDOW));
dc.SetTextColor(GetSysColor(COLOR_WINDOWTEXT));
UINT nState = DFCS_BUTTONCHECK;
if (nCheck > 1)
nState |= DFCS_CHECKED;
dc.DrawFrameControl(rcBitmap, DFC_BUTTON, nState);
}
if (lpDrawItemStruct->itemState & ODS_SELECTED)
{
dc.SetBkColor(GetSysColor(COLOR_HIGHLIGHT));
dc.SetTextColor(GetSysColor(COLOR_HIGHLIGHTTEXT));
}
else
{
dc.SetBkColor(GetSysColor(COLOR_WINDOW));
dc.SetTextColor(GetSysColor(COLOR_WINDOWTEXT));
}
dc.ExtTextOut(0, 0, ETO_OPAQUE, &rcText, 0, 0, 0);
dc.DrawText(' ' + strText, strText.GetLength() + 1, &rcText, DT_SINGLELINE | DT_VCENTER | DT_END_ELLIPSIS);
if ((lpDrawItemStruct->itemState & (ODS_FOCUS | ODS_SELECTED)) == (ODS_FOCUS | ODS_SELECTED))
dc.DrawFocusRect(&rcText);
dc.Detach();
}
void CSWCheckComboBox::CheckAll(int nCheck)
{
for (int nIndex = 0; nIndex < GetCount(); nIndex++)
SetCheck(nIndex, nCheck);
}
LRESULT CSWCheckComboBox::OnGetText(WPARAM wParam, LPARAM lParam)
{
CString strSelText = UpdateCheckedText(FALSE);
if (lParam == 0)
return S_OK;
lstrcpyn((LPSTR)lParam, strSelText, (int)wParam);
return strSelText.GetLength();
}
LRESULT CSWCheckComboBox::OnGetTextLength(WPARAM, LPARAM)
{
CString strSelText = UpdateCheckedText(FALSE);
return strSelText.GetLength();
}
CString CSWCheckComboBox::UpdateCheckedText(BOOL bReupdate/* = TRUE*/)
{
static CString s_strSelText = _T("");
if (bReupdate)
{
// 获取系统默认分隔符
TCHAR szBuffer[10] = { 0 };
GetLocaleInfo(LOCALE_USER_DEFAULT, LOCALE_SLIST, szBuffer, sizeof(szBuffer));
CString strSeparator = szBuffer;
if (strSeparator.GetLength() == 0)
strSeparator = ';';
strSeparator.TrimRight();
strSeparator += ' ';
CString strSelText;
for (int nIndex = 0; nIndex < GetCount(); nIndex++)
{
if (GetItemData(nIndex)) {
CString strItem;
GetLBText(nIndex, strItem);
if (!strSelText.IsEmpty())
strSelText += strSeparator;
strSelText += strItem;
}
}
s_strSelText = strSelText;
}
return s_strSelText;
}
int CSWCheckComboBox::SetCheck(int nIndex, int nCheck, BOOL bRepaint/* = TRUE*/)
{
int nItem = SetItemData(nIndex, (DWORD)nCheck);
if (nItem == CB_ERR)
return CB_ERR;
UpdateCheckedText();
if (bRepaint)
{
Invalidate(FALSE);
RedrawWindow();
}
return nItem;
}
BOOL CSWCheckComboBox::GetCheck(int nIndex)
{
return (BOOL)GetItemData(nIndex);
}
调用源码::OnInitDialog():
//选择下拉框
m_combobox3.SubclassDlgItem(IDC_COMBO5, this);
m_combobox3.AddString(_T("苹果"));
m_combobox3.AddString(_T("橘子"));