VC++ CComboBox自绘(选择下拉列表框)

2023-11-19

效果图:

头文件定义(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("橘子"));

 

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

VC++ CComboBox自绘(选择下拉列表框) 的相关文章

随机推荐

  • mqttxieyi

    Mqtt概述 Mqtt开发最初是用于卫星通讯监控输油管道的项目 一种用于嵌入式设备的通讯协议 这种通讯协议必须满足以下条件 易于实现 数据传输的服务质量可控 占用带宽小 传输数据内容不可预知 设备连接状态可知 MQTT 从诞生之初就是专为低
  • 使用PyCharm进行Python远程调试

    背景描述 在机房中 服务器通过ADB与多台Android设备相连接 并通过Python应用程序 QMSInterceptor 对Android设备进行任务调度 在开发环境中对QMSInterceptor调试完毕后 上传至服务器 发现程序运行
  • Linux基础介绍

    Linux的创始人Linus Torvalds Linux的官方标准发音为 lin ks Linux和Unix是非常像的 Linux就是根据Unix演变过来的 Linux是免费的 其实只是说Linux的内核免费 在Linux内核的基础上产生
  • JAVA协同过滤推荐算法

    1 什么是协同过滤 在推荐系统众多方法中 基于用户的协同过滤推荐算法是最早诞生的 原理也较为简单 该算法1992年提出并用于邮件过滤系统 两年后1994年被 GroupLens 用于新闻过滤 一直到2000年 该算法都是推荐系统领域最著名的
  • WPF TextBox 加默认提示文字

  • C语言pcre库的使用及验证IP地址的合法性

    PCRE是一个用C语言编写的正则表达式函数库 它十分易用 同时功能也很强大 性能超过了POSIX正则表达式库和一些经典的正则表达式库 在使用PCRE库时 首先肯定是需要安装pcre的 不过一般的系统都会有自带的PCRE库 不过如果想使用最新
  • Task1:李宏毅深度学习P1-P2

    这次借在Datawhale组队学习的机会补全一下机器学习上一些知识的漏洞 主要是标注一下自己需要注意的地方在这与大家分享 今日分享的是李宏毅深度学习Part1 2中自己之前不太重视的地方 1 在对机器学习的各类概念介绍时 还是能看出与国内授
  • 字符串09--表示数值的字符串

    字符串09 表示数值的字符串 jz53 题目概述 解析 参考答案 注意事项 说明 题目概述 算法说明 请实现一个函数用来判断字符串是否表示数值 包括整数和小数 例如 字符串 100 5e2 123 3 1416 和 1E 16 都表示数值
  • Sublime Text 常用快捷键

    文章目录 通用 General 编辑 Editing 选择 Selecting 查找 替换 Finding Replacing 跳转 Jumping 窗口 Window 屏幕 Screen 工欲善其事 必先利其器 本文收集 Sublime
  • 解决报错:Uncaught TypeError: Cannot read properties of undefined (reading ‘install‘)

    在做vue2项目时出现如下错误 页面空白且控制台出现如下错误 报错内容 Uncaught TypeError Cannot read properties of undefined reading install at Vue use vu
  • Anaconda + jupyter notebook + jupyter lab环境配置

    1 更换源 1 1 pip源 pip config set global index url https pypi tuna tsinghua edu cn simple pip config set install trusted hos
  • SQL SERVER2008存储过程加密与解密

    前言 我们在设置数据库存储过程时经常会用到加密 如果遇到版本更新需要修改存储过程时 如果设计数据库时的存储过程没有留存 所以就必须用到存储过程的解密了 原来自己有个解密存储过程在SQL2000下应用无问题 后来升级到SQL2008后不好用了
  • 4.网络爬虫—Post请求(实战演示)

    网络爬虫 Post请求实战演示 POST请求 GET请求 POST请求和GET请求的区别 获取二进制数据 爬 百度官网 https www baidu com logo实战 发送post请求 百度翻译实战 使用session发送请求 模拟登
  • 微信小程序部署到线上环境

    微信小程序部署到线上环境 一 微信小程序申请 申请 并认证 未认证不能发布 认证需要300元 目前只支持企业认证 详细见官网说明 https mp weixin qq com cgi bin registermidpage action i
  • mac os mysql忘记root密码_mac上mysql报错以及root密码忘记解决办法

    1 对于前者ERROR 2002 HY000 Can t connect to local MySQL server through socket tmp mysql sock 2 这个错误 一般是mysql服务没开 命令行下执行sudo
  • java8的时期和时间

    文章目录 旧版日期时间的问题 新版日期时间介绍 Java util date java sql date SimpleDateFormatter calendar java8日期 DateTimeFormatter 计算 java8之前 j
  • Python学习 第五章 图形界面设计

    第五章 图形界面设计 1 常用的 Python GUI 库 1 1 Tkinter 1 2 wxPython 1 3 创建GUI程序 2 创建Windows窗口 3 几何布局管理器 3 1 pack 包装 3 2 grid 网格 3 3 p
  • leetcode移动零c++

    给定一个数组 nums 编写一个函数将所有 0 移动到数组的末尾 同时保持非零元素的相对顺序 示例 输入 0 1 0 3 12 输出 1 3 12 0 0 说明 必须在原数组上操作 不能拷贝额外的数组 尽量减少操作次数 整体思路 题目中都出
  • 软件项目经理的基本职责

    软件项目经理的基本职责 1 制定项目计划 并根据各种变化修改项目计划2 实施 项目的管理 开发 质量保证过程 确保客户的成本 进度 绩效和质量目标 3 制定有效的项目决策过程4 确保在项目生命周期中遵循是实施公司的管理和质量政策5 选择一个
  • VC++ CComboBox自绘(选择下拉列表框)

    效果图 头文件定义 CSWCheckComboBox h pragma once class CSWCheckComboBox public CComboBox DECLARE DYNAMIC CSWCheckComboBox 成员私有结构