关于ComboBox子项自绘的问题

yb0312 2016-08-06 11:01:02
ComboBox已设置为CBS_OWNERDRAWFIXED方式,响应消息WM_DRAWITEM,完成了下拉子项的自绘。
关于选中项的自绘,应该响应什么消息和如何来完成呢?我查了下,只有WM_DRAWITEM消息才包含子项自绘的相关信息,而WM_DRAWITEM消息只会在点击下拉按钮时才会触发。
我需要在创建combobox和选中子项后,绘制相应项,应该如何来完成呢?
...全文
229 9 打赏 收藏 转发到动态 举报
写回复
用AI写文章
9 条回复
切换为时间正序
请发表友善的回复…
发表回复
yb0312 2016-08-08
  • 打赏
  • 举报
回复
引用 1 楼 zgl7903 的回复:
那应该 再子类化 Edit (Simple or Drop-down)或 Static (Drop-down list) 控件, 再绘制 参考MSDN文档 How to subclass CListBox and CEdit inside of CComboBox
不能触发WM_COLORSTATIC事件,能触发WM_COLORLISTBOX。 我这样做的: 创建NCmbBox类,用createwindow新建一个combobox控件,然后自定义控件处理程序NCmbProc。在主窗口中的WM_CREATE事件中,显示控件。
// 创建控件
BOOL CNCmbBox::Create(HWND hwnd, UINT uid,RECT rec)
{
	HINSTANCE hinst = (HINSTANCE)GetWindowLongPtr(hwnd, GWLP_HINSTANCE);
	//创建窗口
	mWnd = CreateWindow(
		L"combobox",	//控件类型
		L"",			//控件标题
		WS_CHILD | WS_VISIBLE | WS_OVERLAPPED| WS_VSCROLL | CBS_DROPDOWNLIST | CBS_HASSTRINGS | CBS_OWNERDRAWFIXED,	//样式
		rec.left,				//x坐标
		rec.top,				//y坐标
		rec.right - rec.left,	//宽度
		rec.bottom - rec.top,	//高度
		hwnd,					//父窗口句柄
		(HMENU)uid,				//控件ID号
		hinst,					//程序全局句柄
		NULL					//lParam 传递参数
	);
	//显示控件
	ShowWindow(mWnd, SW_SHOW);
	//更新控件
	UpdateWindow(mWnd);
	//消息传递参数
	MCTLPARAMS* pCtlParams = new MCTLPARAMS;
	pCtlParams->mUid = uid;
	pCtlParams->mPtr = this;
	//定义消息处理程序
	pCtlParams->mProc = (WNDPROC)SetWindowLongPtr(mWnd, GWLP_WNDPROC, (LONG)NCmbProc);	
	//保存自定义数据到控件窗口的userdata中
	SetWindowLongPtr(mWnd, GWLP_USERDATA, (LONG)pCtlParams);
	
	if (m_mColors.size() == 0) InitalColorArray();
	list<NCOLORS*>::iterator ite;
	for (ite = m_mColors.begin(); ite != m_mColors.end(); ite++)
	{
		//add string
		ComboBox_AddString(
			mWnd,
			(LPARAM)((NCOLORS*)(*ite))->m_cColor
		);
	}
	return 0;
}
控件消息处理:
LRESULT APIENTRY  CNCmbBox::NCmbProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
{	
	MCTLPARAMS* mCtlParams = (MCTLPARAMS*)(GetWindowLong(hwnd, GWLP_USERDATA));
	WNDPROC nProc = mCtlParams->mProc;	
	switch (msg)
	{
		case WM_DRAWITEM:
		{
			if (((LPDRAWITEMSTRUCT)lParam)->itemState& ODS_SELECTED)  //如果当前项被选中
			{
				SetBkColor(((LPDRAWITEMSTRUCT)lParam)->hDC, GetSysColor(COLOR_HIGHLIGHT));
				SetTextColor(((LPDRAWITEMSTRUCT)lParam)->hDC,
					GetSysColor(COLOR_WINDOWTEXT) & 0x00FFFFFF
				);
			}
			else
			{
				SetBkColor(((LPDRAWITEMSTRUCT)lParam)->hDC, GetSysColor(COLOR_WINDOW));
				SetTextColor(((LPDRAWITEMSTRUCT)lParam)->hDC,GetSysColor(COLOR_WINDOWTEXT));
			}
			mCtlParams->mPtr->DrawItem(
				((LPDRAWITEMSTRUCT)lParam)->hDC,
				((LPDRAWITEMSTRUCT)lParam)->itemID,
				((LPDRAWITEMSTRUCT)lParam)->rcItem
			);	
			break;
		}
		case WM_COMMAND:
		{
			if (HIWORD(wParam) == CBN_SELCHANGE)
			{
				//id = ComboBox_GetCurSel(hwnd);
				//_itow_s(id, str, 10);
				//MessageBox(hwnd, str, NULL, NULL);
				//ComboBox_SetCurSel(hwnd, id);
			}
			break;
		}
		case WM_CTLCOLORSTATIC:
		{
			Sleep(0);
			break;
		}
		case WM_MEASUREITEM:
		{
			((LPMEASUREITEMSTRUCT)lParam)->itemHeight = 36;
			break;
		}
		default:
		{
			break;
		}
	}	
	return CallWindowProc(nProc,hwnd, msg, wParam, lParam);    //传递消息给主窗口
}
schlafenhamster 2016-08-08
  • 打赏
  • 举报
回复

// 子类化 ComboBox 中的 edit 过程, CBS_DROPDOWN 
HWND    m_hCbEdit=0; 
WNDPROC CBoldEditProc;
LRESULT CALLBACK CbEditProc(HWND hWnd, UINT Msg, WPARAM wParam, LPARAM lParam) 
{
	switch(Msg)
	{
		case WM_KEYDOWN:
			if(wParam==VK_RETURN) OutputDebugString("VK_RETURN\r\n");
		break;
	}
	return CallWindowProc(CBoldEditProc, hWnd, Msg, wParam, lParam);
}
schlafenhamster 2016-08-08
  • 打赏
  • 举报
回复

HWND CreateCB(HWND parentWnd)
{
	HWND hComboBox=0;
	hComboBox = CreateWindow("COMBOBOX",
                NULL,// CBS_DROPDOWNLIST
                WS_CHILD | WS_VSCROLL | WS_TABSTOP |  CBS_DROPDOWN ,//|CBS_SORT,
                330, 40, 90, 140, 
                parentWnd, (HMENU)IDC_COMBOBOX, 
                (HINSTANCE) GetWindowLong(parentWnd, GWL_HINSTANCE), 
                NULL);
//
	            ShowWindow(hComboBox,SW_SHOW);
	            SendMessage(hComboBox,CB_ADDSTRING ,0,(LPARAM)"你好");
	            SendMessage(hComboBox,CB_ADDSTRING ,0,(LPARAM)"我好");
	            SendMessage(hComboBox,CB_ADDSTRING ,0,(LPARAM)"他好");
	            SendMessage(hComboBox,CB_ADDSTRING ,0,(LPARAM)"大家好");
	return hComboBox;
}
case WM_CREATE: { ... m_hComboBox=CreateCB(hwnd); CBoldProc = (WNDPROC)SetWindowLong(m_hComboBox, GWL_WNDPROC, (LONG)CBProc);
schlafenhamster 2016-08-08
  • 打赏
  • 举报
回复

//子类化 ComboBox 过程
WNDPROC CBoldProc;
LRESULT CALLBACK CBProc(HWND hWnd, UINT Msg, WPARAM wParam, LPARAM lParam) 
{ 
	char promp[40];
//
	switch(Msg)
    {    
	case WM_CTLCOLOREDIT:
		if(m_hCbEdit==0)
		{
			m_hCbEdit=(HWND) lParam;
	  		CBoldEditProc = (WNDPROC)SetWindowLong(m_hCbEdit, GWL_WNDPROC, (LONG)CbEditProc); 
		}
		break;
	case WM_CHAR:// only CBS_DROPDOWNLIST
		if(wParam==VK_RETURN)
		{
			OutputDebugString("VK_RETURN\n");
		}
		break;
	case WM_PAINT://0F
//		OutputDebugString("WM_LBUTTONDOWN\n");
	break;
	case WM_SETCURSOR://20
//		OutputDebugString("WM_LBUTTONDOWN\n");
	break;
	case WM_MOUSEFIRST://200
//		OutputDebugString("WM_LBUTTONDOWN\n");
	break;
	case WM_LBUTTONDOWN:
		OutputDebugString("WM_LBUTTONDOWN\n");
	break;
	case WM_LBUTTONDBLCLK:
//		OutputDebugString("WM_LBUTTONDBLCLK\n");
	break;
	case WM_RBUTTONDOWN:
//		OutputDebugString("WM_RBUTTONDOWN\n");
	break;
	case WM_RBUTTONDBLCLK: 
//		OutputDebugString("WM_RBUTTONDBLCLK\n");
	break;
	case WM_NCHITTEST: //84
//		OutputDebugString("WM_NCHITTEST\n");
	break;
	case WM_NOTIFY://4E
	{
		OutputDebugString("WM_NOTIFY\n");
	}
	break;
	default :
		sprintf(promp,"Msg %04X\n",Msg);
		//OutputDebugString(promp);
		break;

	}
	return CallWindowProc(CBoldProc, hWnd, Msg, wParam, lParam);
}
yb0312 2016-08-08
  • 打赏
  • 举报
回复
引用 5 楼 schlafenhamster 的回复:
1 派生你的 combobox class CSuperComboBox : public CComboBox 2. 那么 CSuperComboBox 有 一个 =WM_CTLCOLOR 这个=表示 反射 消息 3 消息响应 // CSuperComboBox message handlers HBRUSH CSuperComboBox::OnCtlColor(CDC* pDC, CWnd* pWnd, UINT nCtlColor) { // TODO: Change any attributes of the DC here if (nCtlColor == CTLCOLOR_LISTBOX) {//ListBox control,It is a COMBOLBOX,not a normal listbox.Besides, //It is not a child window of combobox. if (m_listbox.GetSafeHwnd() == NULL) { m_listbox.SubclassWindow(pWnd->GetSafeHwnd()); //too later to change the sytle! // no vscroll !!! m_listbox.ModifyStyle(0,WS_HSCROLL|LBS_MULTICOLUMN); //you have to create a new list box ? //see "Dynamically re-creating a list box" code project. RecreateComboLBox(&m_listbox);// no messages ? } } if (nCtlColor == CTLCOLOR_EDIT) { m_hEdit=pWnd->GetSafeHwnd(); } // HBRUSH hbr = CComboBox::OnCtlColor(pDC, pWnd, nCtlColor); return hbr; } 4. 头文件 中 是 protected: //{{AFX_MSG(CSuperComboBox) afx_msg HBRUSH OnCtlColor(CDC* pDC, CWnd* pWnd, UINT nCtlColor);
谢谢你的回复,不过我的程序是基于win32的,无法调用ccmobobox类。
schlafenhamster 2016-08-08
  • 打赏
  • 举报
回复
1 派生你的 combobox class CSuperComboBox : public CComboBox 2. 那么 CSuperComboBox 有 一个 =WM_CTLCOLOR 这个=表示 反射 消息 3 消息响应 // CSuperComboBox message handlers HBRUSH CSuperComboBox::OnCtlColor(CDC* pDC, CWnd* pWnd, UINT nCtlColor) { // TODO: Change any attributes of the DC here if (nCtlColor == CTLCOLOR_LISTBOX) {//ListBox control,It is a COMBOLBOX,not a normal listbox.Besides, //It is not a child window of combobox. if (m_listbox.GetSafeHwnd() == NULL) { m_listbox.SubclassWindow(pWnd->GetSafeHwnd()); //too later to change the sytle! // no vscroll !!! m_listbox.ModifyStyle(0,WS_HSCROLL|LBS_MULTICOLUMN); //you have to create a new list box ? //see "Dynamically re-creating a list box" code project. RecreateComboLBox(&m_listbox);// no messages ? } } if (nCtlColor == CTLCOLOR_EDIT) { m_hEdit=pWnd->GetSafeHwnd(); } // HBRUSH hbr = CComboBox::OnCtlColor(pDC, pWnd, nCtlColor); return hbr; } 4. 头文件 中 是 protected: //{{AFX_MSG(CSuperComboBox) afx_msg HBRUSH OnCtlColor(CDC* pDC, CWnd* pWnd, UINT nCtlColor);
yb0312 2016-08-08
  • 打赏
  • 举报
回复
引用 3 楼 VisualEleven 的回复:
The WM_CTLCOLORLISTBOX message is sent to the parent window of a list box before the system draws the list box. By responding to this message, the parent window can set the text and background colors of the list box by using the specified display device context handle. A window receives this message through its WindowProc function.
确实是这样,我原意是想把控件消息处理都封装在控件类中,看来实现不了了。 再请教个问题,当我把控件的消息处理程序绑定到控件的HWND句柄中时,自绘模式下,windows不会处理选中项的绘制。但是当我把处理程序绑定到主窗口的HWND句柄上时,windows就会处理相关绘制。除了绑定主窗口HWND外,有没有办法通知父窗口完成选中项绘制呢?
SetWindowLongPtr(mWnd, GWLP_WNDPROC, (LONG)NCmbProc);
Eleven 2016-08-08
  • 打赏
  • 举报
回复
The WM_CTLCOLORLISTBOX message is sent to the parent window of a list box before the system draws the list box. By responding to this message, the parent window can set the text and background colors of the list box by using the specified display device context handle. A window receives this message through its WindowProc function.
zgl7903 2016-08-06
  • 打赏
  • 举报
回复
那应该 再子类化 Edit (Simple or Drop-down)或 Static (Drop-down list) 控件, 再绘制 参考MSDN文档 How to subclass CListBox and CEdit inside of CComboBox

16,471

社区成员

发帖
与我相关
我的任务
社区描述
VC/MFC相关问题讨论
社区管理员
  • 基础类社区
  • Web++
  • encoderlee
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告

        VC/MFC社区版块或许是CSDN最“古老”的版块了,记忆之中,与CSDN的年龄几乎差不多。随着时间的推移,MFC技术渐渐的偏离了开发主流,若干年之后的今天,当我们面对着微软的这个经典之笔,内心充满着敬意,那些曾经的记忆,可以说代表着二十年前曾经的辉煌……
        向经典致敬,或许是老一代程序员内心里面难以释怀的感受。互联网大行其道的今天,我们期待着MFC技术能够恢复其曾经的辉煌,或许这个期待会永远成为一种“梦想”,或许一切皆有可能……
        我们希望这个版块可以很好的适配Web时代,期待更好的互联网技术能够使得MFC技术框架得以重现活力,……

试试用AI创作助手写篇文章吧