社区
界面
帖子详情
MFC 可以用类 添加列表控件的 OnCustomDraw 消息吗?
ekisstherain
2010-04-14 10:52:01
如题,只是想知道可不可以,
如果可以的话,应该是那个消息,
我在类那映射表里没有找到对应的消息哦
还想知道一下,如果没有的话,是不是自己打上去,还是应该怎样做呢???
还有,我想在列表中做不同的行用不同的背景色显示出来,应该怎么做好呢,
谢谢高手回答啊~~~~~~~~~~~
...全文
152
10
打赏
收藏
MFC 可以用类 添加列表控件的 OnCustomDraw 消息吗?
如题,只是想知道可不可以, 如果可以的话,应该是那个消息, 我在类那映射表里没有找到对应的消息哦 还想知道一下,如果没有的话,是不是自己打上去,还是应该怎样做呢??? 还有,我想在列表中做不同的行用不同的背景色显示出来,应该怎么做好呢, 谢谢高手回答啊~~~~~~~~~~~
复制链接
扫一扫
分享
转发到动态
举报
写回复
配置赞助广告
用AI写文章
10 条
回复
切换为时间正序
请发表友善的回复…
发表回复
打赏红包
hhpltby2007
2010-06-03
打赏
举报
回复
~~~
向立天
2010-04-25
打赏
举报
回复
您好
我是本版版主
此帖已多日无人关注
请您及时结帖
如您认为问题没有解决可按无满意结帖处理
另外本版设置了
疑难问题汇总帖
并已在版面置顶
相关规定其帖子中有说明
您可以根据规定提交您帖子的链接
如您目前不想结帖只需回帖说明
我们会删除此结帖通知
见此回复三日内无回应
我们将强制结帖
相关规定详见界面
界面版关于版主结帖工作的具体办法
向立天
2010-04-17
打赏
举报
回复
[Quote=引用 6 楼 ekisstherain 的回复:]
没有人能看懂啊
[/Quote]
我不是告诉你了么
给你自己的listctrl类链接反射消息
ON_NOTIFY_REFLECT(NM_CUSTOMDRAW, OnCustomDraw)
schlafenhamster
2010-04-17
打赏
举报
回复
//.h
//}}AFX_MSG
afx_msg void OnCustDrawList(NMHDR *pNMHDR,LRESULT *pResult);
//.cpp
//}}AFX_MSG_MAP
ON_NOTIFY(NM_CUSTOMDRAW, IDC_LIST,OnCustDrawList)
//
void CxxxDlg::OnCustDrawList(NMHDR *pNMHDR,LRESULT *pResult)
{
// TODO: Add your message handler code here and/or call default
*pResult=CDRF_NOTIFYITEMDRAW ;
//| CDRF_NOTIFYSUBITEMDRAW | CDRF_NOTIFYPOSTPAINT| CDRF_NOTIFYPOSTERASE;
LPNMLVCUSTOMDRAW pDraw=(LPNMLVCUSTOMDRAW)pNMHDR;
DWORD dwDrawStage=pDraw->nmcd.dwDrawStage;
int nID=pDraw->nmcd.dwItemSpec;//
int selID=m_List.GetNextItem(-1,LVNI_SELECTED);
int subItem=pDraw->iSubItem;
//
if((nID==selID) && (subItem==0))
{ // afxDump << selID << ";" << subItem <<"\n";
CDC* pdc=CDC::FromHandle(pDraw->nmcd.hdc);
//
CRect rc;
m_List.GetItemRect(selID,&rc,LVIR_LABEL);
CString txt=m_List.GetItemText(selID,0);
//
CSize sz=pdc->GetOutputTextExtent(txt);
rc.right=rc.left+sz.cx+8;
rc.DeflateRect(1,1);
//
DWORD clr=GetSysColor(COLOR_HIGHLIGHT);
pdc->FillSolidRect(&rc,clr);
//
pdc->SetTextColor(RGB(255,255,255));//white
pdc->SetBkColor(clr);
//
if(!m_bFontInited)
{
m_bFontInited=TRUE;
CDC *pDC=GetDC();
int cyFont=-MulDiv(8,pDC->GetDeviceCaps(LOGPIXELSY),72);//cyFont=-11
m_hItalicFont.CreateFont(cyFont-12,0,0,0,FW_THIN,TRUE,
FALSE,FALSE,0,0,0,0,0,_T("Arial"));
}
CFont* pfnt=pdc->GetCurrentFont();
pdc->SelectObject(&m_hItalicFont);//pfnt);
//
pdc->TextOut(rc.left,rc.top,txt);
*pResult |= CDRF_SKIPDEFAULT;
}
}
ekisstherain
2010-04-17
打赏
举报
回复
没有人能看懂啊
向立天
2010-04-15
打赏
举报
回复
ON_NOTIFY_REFLECT(NM_CUSTOMDRAW, OnCustomDraw)
soswaidao
2010-04-15
打赏
举报
回复
只能帮楼主顶一下
Eleven
2010-04-15
打赏
举报
回复
DrawItem()?这个虚函数, WM_DRAWITEM 消息
z8y8x
2010-04-15
打赏
举报
回复
我是来接分的
ekisstherain
2010-04-15
打赏
举报
回复
WM_DRAWITEM 消息 这个映射如下函数啊:
void CMyList::OnDrawItem(int nIDCtl, LPDRAWITEMSTRUCT lpDrawItemStruct)
{
// TODO: Add your message handler code here and/or call default
CListCtrl::OnDrawItem(nIDCtl, lpDrawItemStruct);
}
我要的是这个哦:
void CMyList::OnNMCustomdraw(NMHDR *pNMHDR, LRESULT *pResult)
{
// TODO: Add your control notification handler code here
*pResult = CDRF_DODEFAULT;
NMLVCUSTOMDRAW * lplvdr=(NMLVCUSTOMDRAW*)pNMHDR;
NMCUSTOMDRAW &nmcd = lplvdr->nmcd;
switch(lplvdr->nmcd.dwDrawStage)
{
case CDDS_PREPAINT:
*pResult = CDRF_NOTIFYITEMDRAW;
break;
case CDDS_ITEMPREPAINT:
{
COLORREF ItemColor;
if( MapItemColor.Lookup(nmcd.dwItemSpec, ItemColor))
{
lplvdr->clrTextBk = ItemColor;
*pResult = CDRF_DODEFAULT;
}
}
break;
}
}
Ctreectrl树形
控件
的勾选联动效果
Ctreectrl树形
控件
的勾选联动效果,完成树形
控件
的全选,全部取消等能,只需要继承这个类就可以了
VC之美化界面篇本文专题讨论VC中的界面美化,适用于具有中等VC水平的读者。读者最好具有以下VC基础:
VC之美化界面篇 作者:白乔 链接:http://vcer.net/1046595482643.html 本文专题讨论VC中的界面美化,适用于具有中等VC水平的读者。读者最好具有以下VC基础: 1. 大致了解
MFC
框架的基本运作原理; 2. 熟悉Windows
消息
机制,熟悉
MFC
的
消息
映射和反射机制; 3. 熟悉OOP理论和技术; 本文根据笔者多年的开发经验,并结合简单的例子一一展开,希望对读者有所帮助。 1 美化界面之开题篇 相信使用过《金山毒霸》、《瑞星杀毒》软件的读者应该还记得它们的精美界面: 图1 瑞星杀毒软件的精美界面 程序的功能如何如何强大是一回事,它的用户界面则是另一回事。千万不要忽视程序的用户界面,因为它是给用户最初最直接的印象,丑陋的界面、不友好的风格肯定会影响用户对软件程序的使用。 “受之以鱼,不若授之以渔”,本教程并不会向你推荐《瑞星杀毒软件》精美界面的具体实现,而只是向你推荐一些常用的美化方法。 2 美化界面之基础篇 美化界面需要先熟悉Windows下的绘图操作,并明白Windows的幕后绘图操作,才能有的放矢,知道哪些可以使用,知道哪些可以避免…… 2.1 Windows下的绘图操作 熟悉DOS的读者可能就知道:DOS下面的图形操作很方便,进入图形模式,整个屏幕就是你的了,你希望在哪画个点,那个地方就会出现一个点,红的、或者黄的,随你的便。你也可以花点时间画个按钮,画个你自己的菜单,等等…… Windows本身就是图形界面,所以Windows下面的绘图操作功能更丰富、简单。要了解Windows下的绘图操作,要实现Windows界面的美化,就必须了解
MFC
封装的设备环境类和图形对象类。 2.1.1 设备环境类 Windows下的绘图操作说到底就是DC操作。DC(Device Context设备环境)对象是一个抽象的作图环境,可能是对应屏幕,也可能是对应打印机或其它。这个环境是设备无关的,所以你在对不同的设备输出时只需要使用不同的设备环境就行了,而作图方式可以完全不变。这也就是Windows的设备无关性。
MFC
的CDC类封装了Windows API 中大部分的画图函数。CDC的常见操作函数包括:
Draw
ing-Attribute Functions:绘图属性操作,如:设置透明模式 Mapping Functions:映射操作 Coordinate Functions:坐标操作 Clipping Functions:剪切操作 Line-Output Functions:画线操作 Simple
Draw
ing Functions:简单绘图操作,如:绘制矩形框 Ellipse and Polygon Functions:椭圆/多边形操作 Text Functions:文字输出操作 Printer Escape Functions:打印操作 Scrolling Functions:滚动操作 *Bitmap Functions:位图操作 *Region Functions:区域操作 *Font Functions:字体操作 *Color and Color Palette Functions:颜色/调色板操作 其中,标注*项会用到相应的图形对象类,参见2.1.2内容。 2.1.2 图形对象类 设备环境不足以包含绘图功能所需的所有绘图特征,除了设备环境外, Windows还有其他一些图形对象用来储存绘图特征。这些附加的功能包括从画线的宽度和颜色到画文本时所用的字体。图形对象类封装了所有六个图形对象。 下面的表格列出了
MFC
的图形对象类:
MFC
类 图形对象句柄 图形对象目的 CBitmap HBITMAP 内存中的位图 CBrush HBRUSH 画刷特性—填充某个图形时所使用的颜色和模式 CFont HFONT 字体特性—写文本时所使用的字体 CPalette HPALETTE 调色板颜色 CPen HPEN 画笔特性—画轮廓时所使用的线的粗细 CRgn HRGN 区域特性—包括定义它的点 表1 图形对象类和它们封装的句柄 使用CDC和图形对象类,在Windows里绘图还算是很简单的。观察以下的画面: 图2 使用CDC绘制出的按钮 该画面通过以下代码自行绘制的假按钮: BOOL CUi1View::PreCreateWindow(CREATESTRUCT& cs) { //设置背景色 //CBrush CUi1View::m_Back m_Back.CreateSolidBrush(::GetSysColor(COLOR_3DFACE)); cs.lpszClass = AfxRegisterWndClass(0, 0, m_Back, NULL); return CView::PreCreateWindow(cs); } int CUi1View::OnCreate(LPCREATESTRUCT lpCreateStruct) { if (CView::OnCreate(lpCreateStruct) == -1) return -1; //创建字体 //CFont CUi1View::m_Font m_Font.CreatePointFont(120, "Impact"); return 0; } void CUi1View::On
Draw
(CDC* pDC) { //绘制按钮框架 pDC->
Draw
FrameControl(CRect(100, 100, 220, 160), DFC_BUTTON, DFCS_BUTTONPUSH); //输出文字 pDC->SetBkMode(TRANSPARENT); pDC->TextOut(120, 120, "Hello, CFan!"); } 呵呵,不好意思,这并不是真的Windows按钮,它只是一个假的空框子,当用户在按钮上点击鼠标时,放心,什么事情都不会发生。 2.2 Windows的幕后绘图操作 在Window中,如果所有的界面操作都由用户代码来实现,那将是一个很浩大的工程。笔者曾经在DOS设计过窗口图形界面,代码上千行,但实现的界面还是很古板、难看,除了我那个对编程一窍不通的女友,没有一个人欣赏它L;而且,更要命的是,操作系统,包括别的应用程序并不认识你的界面元素,这才是真正悲哀的。认识这些界面的只有你的程序,图2中的按钮永远只是一个无用的框子。 有了Windows,一切都好办了,Windows将诸如按钮、菜单、工具栏等等这些通用界面的绘制及动作都交给了系统,程序员就不用花心思再画那些按钮了,可以将更多的精力放在程序的功能实现方面。 所有的标准界面元素都被Windows封装好了。Windows知道怎么画你的菜单以及你的标注着“Hello, Cfan!”的按钮。当CFan某个快乐的小编(譬如:小飞)点击这个按钮的时候,Windows也明白按钮按下去的时候该有的模样,甚至,当这个友好的按钮获取焦点时,Windows也会不失时机地为它准备一个虚框…… 有利必有弊。你的不满这时候产生了:你既想使用Windows的True Button,可也嫌它的界面不够好看,譬如,你喜欢用蓝色的粗体表达你对CFan的无限情怀(正如图2那样)——人心不足,有办法吗?有的。 3 美化界面之实现篇 Windows还是给程序员留下了很多后门,通过一些途径还是可以美化界面的。本章节我们系统学习一下Windows界面美化的实现。 3.1 美化界面的途径 如何以合法的手段来达到美化界面的效果?一般美化界面的方法包括: 1. 使用
MFC
类的既有函数,设定界面属性; 2. 利用Windows的
消息
机制,截获有用的Windows的
消息
。通过
MFC
的
消息
映射(Message Mapping)和反射(Message Reflecting)机制,在Windows准备或者正在绘制该元素时,偷偷修改它的状态和行为,譬如:让按钮的边框为红色; 3. 利用
MFC
类的虚函数机制,重载有用的虚函数。在
MFC
框架调用该函数的时候,重新定义它的状态和行为; 一般来说,应用程序可以通过以下两种途径来实现以上的方法: 1. 在父窗口里,截获自身的或者由子元素(包括
控件
和菜单等元素)传递的关于界面绘制的
消息
; 2. 子类化子元素,或者为子元素准备一个新的类(一般来说该类必须继承于
MFC
封装的某个标准类,如:CButton)。在该子元素里,截获自身的或者从父窗口反射过来的关于界面绘制的
消息
。譬如:用户可以创建一个CXPButton类来实现具有XP风格的按钮,CXPButton继承于CButton。 对于应用程序,使用CXPButton类的途径相对于对话框窗口和普通窗口分成两种: ① 对话框窗口中,直接将原先绑定按钮的CButton类替换成CXPButton类,或者在绑定变量时直接指定Control类型为CXPButton,如图3所示: 图3 为按钮指定CXPButton类型 ②在普通窗口中,直接创建一个CXPButton类对象,然后在OnCreate()中调用CXPButton的Create方法; 以下的章节将综合地使用以上的方法,请读者朋友留心观察。 3.2 使用
MFC
类的既有函数 在界面美化的专题中,
MFC
也并非一无是处。
MFC
类对于界面美化也做了部分的努力,以下是一些可以使用的,参数说明略去。 CWinApp::SetDialogBkColor void SetDialogBkColor( COLORREF clrCtlBk = RGB(192, 192, 192), COLORREF clrCtlText = RGB(0, 0, 0) ); 指定对话框的背景色和文本颜色。 CListCtrl::SetBkColor CReBarCtrl::SetBkColor CStatusBarCtrl::SetBkColor CTreeCtrl::SetBkColor COLORREF SetBkColor( COLORREF clr ); 设定背景色。 CListCtrl::SetTextColor CReBarCtrl::SetTextColor CTreeCtrl::SetTextColor COLORREF SetTextColor( COLORREF clr ); 设定文本颜色。 CListCtrl::SetBkImage BOOL SetBkImage( LVBKIMAGE* plvbkImage ); BOOL SetBkImage( HBITMAP hbm, BOOL fTile = TRUE, int xOffsetPercent = 0, int yOffsetPercent = 0); BOOL SetBkImage( LPTSTR pszUrl, BOOL fTile = TRUE, int xOffsetPercent = 0, int yOffsetPercent = 0 ); 设定
列表
控件
的背景图片。 CComboBoxEx::SetExtendedStyle CListCtrl::SetExtendedStyle CTabCtrl::SetExtendedStyle CToolBarCtrl::SetExtendedStyle DWORD SetExtendedStyle( DWORD dwExMask, DWORD dwExStyles ); 设置
控件
的扩展属性,例如:设置
列表
控件
属性带有表格线。 图4是个简单应用
MFC
类的既有函数来改善Windows界面的例子: 图4 使用
MFC
类的既有函数美化界面 相关实现代码如下: BOOL CUi2App::InitInstance() { //… //设置对话框背景色和字体颜色 SetDialogBkColor(RGB(128, 192, 255), RGB(0, 0, 255)); //… } BOOL CUi2Dlg::OnInitDialog() { //… //设置
列表
控件
属性带有表格线 DWORD NewStyle = m_List.GetExtendedStyle(); NewStyle |= LVS_EX_GRIDLINES; m_List.SetExtendedStyle(NewStyle); //设置
列表
控件
字体颜色为红色 m_List.SetTextColor(RGB(255, 0, 0)); //填充数据 m_List.InsertColumn(0, "QQ", LVCFMT_LEFT, 100); m_List.InsertColumn(1, "昵称", LVCFMT_LEFT, 100); m_List.InsertItem(0, "5854165"); m_List.SetItemText(0, 1, "白乔"); m_List.InsertItem(1, "6823864"); m_List.SetItemText(1, 1, "Satan"); //… } 嗯,这样的界面还算不错吧? 3.3 使用Windows的
消息
机制 使用
MFC
类的既有函数来美化界面,其功能是有限的。既然Windows是通过
消息
机制进行通讯的,那么我们就可以通过截获一些有用的
消息
来美化我们的界面,以下是一些有用的Windows
消息
: WM_PAINT WM_ERASEBKGND WM_CTLCOLOR* WM_
DRAW
ITEM* WM_MEASUREITEM* NM_CUSTOM
DRAW
* 注意,标注*的
消息
是子元素发送给父窗口的通知
消息
,其它的为窗口或者子元素自身的
消息
。 3.3.1 WM_PAINT WM_PAINT
消息
相信大家都很熟悉,一个窗口要重绘了,就会有一个WM_PAINT
消息
发送给窗口。 可以响应窗口的WM_PAINT,以更改它们的模样。WM_PAINT的映射函数原型如下: afx_msg void OnPaint();
控件
也是窗口,所以
控件
也有WM_PAINT
消息
,通过
消息
映射我们完全可以定义
控件
的界面。如图5所示: 图5 利用WM_ PAINT
消息
美化界面 实现代码也很简单: void CLazyStatic::OnPaint() { CPaintDC dc(this); // device context for painting //什么都不输出,仅仅画一个矩形框 CRect rc; GetClientRect(&rc); dc.Rectangle(rc); } 哈哈,简单吧?不过WM_PAINT确实绝了点,它要求应用程序完成元素界面的所有绘制过程,想象一下如何画出一个完整的
列表
控件
?太烦了吧。一般来说,很少有人喜欢使用WM_PAINT,还有其它更细致的
消息
。 3.3.2 WM_ERASEBKGND Windows在向窗口发送WM_PAINT
消息
之前,总会发送一个WM_ERASEBKGND
消息
通知该窗口擦除背景,默认情况下,Windows将以窗口的背景色清除该窗口。 可以响应窗口(包括子元素)的WM_ERASEBKGND,以更改它们的背景。WM_ERASEBKGND的映射函数原型如下: afx_msg BOOL OnEraseBkgnd( CDC* pDC ); 返回值: 指定背景是否已清除,如果为FALSE,系统将自动清除 参数: pDC指定了绘制操作所使用的设备环境。 图6是个简单的例子,通过OnEraseBkgnd为对话框加载了一副位图背景: 图6 利用WM_ ERASEBKGND
消息
美化界面 实现代码也很简单: BOOL CUi4Dlg::OnInitDialog() { //… //加载位图 //CBitmap m_Back; m_Back.LoadBitmap(IDB_BACK); //… } BOOL CUi4Dlg::OnEraseBkgnd(CDC* pDC) { CDC dc; dc.CreateCompatibleDC(pDC); dc.SelectObject(&m_Back); //获取BITMAP对象 BITMAP hb; m_Back.GetBitmap(&hb); //获取窗口大小 CRect rt; GetClientRect(&rt); //显示位图 pDC->StretchBlt(0, 0, rt.Width(), rt.Height(), &dc, 0, 0, hb.bmWidth, hb.bmHeight, SRCCOPY); return TRUE; } HBRUSH CUi4Dlg::OnCtlColor(CDC* pDC, CWnd* pWnd, UINT nCtlColor) { //设置透明背景模式 pDC->SetBkMode(TRANSPARENT); //设置背景刷子为空 return (HBRUSH)::GetStockObject(HOLLOW_BRUSH); } 同时别忘了响应OnCtlColor,否则窗口里面的
控件
就不透明了。OnCtlColor的内容。 3.3.3 WM_CTLCOLOR 在
控件
显示之前,每一个
控件
都会向父对话框发送一个WM_CTLCOLOR
消息
要求获取绘制所需要的颜色。WM_CTLCOLOR
消息
缺省处理函数CWnd::OnCtlColor返回一个HBRUSH类型的句柄,这样,就可以设置前景和背景文本颜色,并为
控件
或者对话框的非文本区域选定一个刷子。 WM_CTLCOLOR的映射函数原型如下: afx_msg HBRUSH OnCtlColor( CDC* pDC, CWnd* pWnd, UINT nCtlColor ); 返回值: 用以指定背景的刷子 参数: pDC指定了绘制操作所使用的设备环境。 pWnd
控件
指针 nCtlColor 指定
控件
类型,其取值如表2所示: 类型值 含义 CTLCOLOR_BTN 按钮
控件
CTLCOLOR_DLG 对话框 CTLCOLOR_EDIT 编辑
控件
CTLCOLOR_LISTBOX
列表
框 CTLCOLOR_MSGBOX
消息
框 CTLCOLOR_SCROLLBAR 滚动条 CTLCOLOR_STATIC 静态
控件
表2 nCtlColor的类型值与含义 作为一个简单的例子,观察以下的代码: BOOL CUi5Dlg::OnInitDialog() { //… //创建字体 //CFont CUi1View::m_Font1, CUi1View::m_Font2 m_Font1.CreatePointFont(120, "Impact"); m_Font3.CreatePointFont(120, "Arial"); return TRUE; // return TRUE unless you set the focus to a control } HBRUSH CUi5Dlg::OnCtlColor(CDC* pDC, CWnd* pWnd, UINT nCtlColor) { HBRUSH hbr = CDialog::OnCtlColor(pDC, pWnd, nCtlColor); if(nCtlColor == CTLCOLOR_STATIC) { //区分静态
控件
switch(pWnd->GetDlgCtrlID()) { case IDC_STATIC1: { pDC->SelectObject(&m_Font1); pDC->SetTextColor(RGB(0, 0, 255)); break; } case IDC_STATIC2: { pDC->SelectObject(&m_Font2); pDC->SetTextColor(RGB(255, 0, 0)); break; } } } return hbr; } 生成的界面如下: 图7 利用WM_CTLCOLOR
消息
美化界面 3.3.4 WM_
DRAW
ITEM OnCtlColor只能修改元素的颜色,但不能修改元素的界面框架,WM_
DRAW
ITEM则可以。 当一个具有Owner
draw
风格的元素(包括按钮、组合框、
列表
框和菜单等)需要显示外观时,该元素会发送一条WM_
DRAW
ITEM
消息
至它的隶属窗口(Owner)。 WM_
DRAW
ITEM的映射函数原型如下: afx_msg void On
Draw
Item( int nIDCtl, LP
DRAW
ITEMSTRUCT lp
Draw
ItemStruct ); 参数: nIDCtl 该
控件
的ID,如果该元素为菜单,则nIDCtl为0 lp
Draw
ItemStruct 指向
DRAW
ITEMSTRUCT结构对象的指针,
DRAW
ITEMSTRUCT的结构定义如下: typedef struct tag
DRAW
ITEMSTRUCT { UINT CtlType; UINT CtlID; UINT itemID; UINT itemAction; UINT itemState; HWND hwndItem; HDC hDC; RECT rcItem; DWORD itemData; }
DRAW
ITEMSTRUCT; CtlType指定了
控件
的类型,其取值如表3所示: 类型值 含义 ODT_BUTTON 按钮
控件
ODT_COMBOBOX 组合框
控件
ODT_LISTBOX
列表
框
控件
ODT_LISTVIEW
列表
视图 ODT_MENU 菜单项 ODT_STATIC 静态文本
控件
ODT_TAB Tab
控件
表3 CtlType的类型值与含义 CtlID 指定自绘
控件
的ID值,该成员不适用于菜单项 itemID表示菜单项ID,也可以表示
列表
框或者组合框中某项的索引值。对于一个空的
列表
框或组合框,该成员的值为?C1。这时应用程序只绘制焦点矩形(该矩形的坐标由rcItem 成员给出)虽然此时
控件
中没有需要显示的项,但是绘制焦点矩形还是很有必要的,因为这样做能够提示用户该
控件
是否具有输入焦点。当然也可以设置itemAction 成员为合适值,使得无需绘制焦点。 itemAction 指定绘制行为,其取值为表4中所示值的一个或者多个的联合: 类型值 含义 ODA_
DRAW
ENTIRE 当整个
控件
都需要被绘制时,设置该值。 ODA_FOCUS 如果
控件
需要在获得或失去焦点时被绘制,则设置该值。此时应该检查itemState成员,以确定
控件
是否具有输入焦点。 ODA_SELECT 如果
控件
需要在选中状态改变时被绘制,则设置该值。此时应该检查itemState 成员,以确定
控件
是否处于选中状态。 表4 itemAction的类型值与含义 itemState 指定了当前绘制项的状态。例如,如果菜单项应该被灰色显示,则可以指定ODS_GRAYED状态标志。其取值为表5中所示值的一个或者多个的联合: 类型值 含义 ODS_CHECKED 标记状态,仅适用于菜单项。 ODS_DEFAULT 默认状态。 ODS_DISABLED 禁止状态。 ODS_FOCUS 焦点状态。 ODS_GRAYED 灰化状态,仅适用于菜单项。 ODS_SELECTED 选中状态。 ODS_HOTLIGHT 仅适用于Windows 98/Me/Windows 2000/XP,热点状态:如果鼠标指针位于
控件
之上,则设置该值,这时
控件
会显示高亮颜色。 ODS_INACTIVE 仅适用于Windows 98/Me/Windows 2000/XP,非激活状态。 ODS_NOACCEL 仅适用于Windows 2000/XP,
控件
是否有快速键。 ODS_COMBOBOXEDIT 在自绘组合框
控件
中只绘制选择区域。 ODS_NOFOCUSRECT 仅适用于Windows 2000/XP,不绘制捕获焦点的效果。 表5 itemState的类型值与含义 hwndItem 指定了组合框、
列表
框和按钮等自绘
控件
的窗口句柄;如果自绘的对象为菜单项,则表示包含该菜单项的菜单句柄。 hDC 指定了绘制操作所使用的设备环境。 rcItem 指定了将被绘制的矩形区域。这个矩形区域就是上面hDC的作用范围。系统会自动裁剪组合框、
列表
框或按钮等
控件
的自绘制区域以外的部分。也就是说rcItem中的坐标点(0,0)指的就是
控件
的左上角。但是系统不裁剪菜单项,所以在绘制菜单项的时候,必须先通过一定的换算得到该菜单项的位置,以保证绘制操作在我们希望的区域中进行。 itemData 对于菜单项,该成员的取值为由CMenu::AppendMenu、CMenu::InsertMenu、CMenu::ModifyMenu等函数传递给菜单的值。 对于
列表
框或这组合框,该成员的取值为由ComboBox::AddString、CComboBox::InsertString、CListBox::AddString或者CListBox::InsertString等函数传递给
控件
的值。 如果ctlType 的取值是ODT_BUTTON或者ODT_STATIC,itemData的取值为0。 图5是个相应的例子,它修改了按钮的界面: 图8 利用WM_
DRAW
ITEM
消息
美化界面 实现代码如下: BOOL CUi6Dlg::OnInitDialog() { //… //创建字体 //CFont CUi1View::m_Font m_Font.CreatePointFont(120, "Impact"); //… } void CUi6Dlg::On
Draw
Item(int nIDCtl, LP
DRAW
ITEMSTRUCT lp
Draw
ItemStruct) { if(nIDCtl == IDC_HELLO_CFAN) { //绘制按钮框架 UINT uStyle = DFCS_BUTTONPUSH; //是否按下去了? if (lp
Draw
ItemStruct->itemState & ODS_SELECTED) uStyle |= DFCS_PUSHED; CDC dc; dc.Attach(lp
Draw
ItemStruct->hDC); dc.
Draw
FrameControl(&lp
Draw
ItemStruct->rcItem, DFC_BUTTON, uStyle); //输出文字 dc.SelectObject(&m_Font); dc.SetTextColor(RGB(0, 0, 255)); dc.SetBkMode(TRANSPARENT); CString sText; m_HelloCFan.GetWindowText(sText); dc.TextOut(lp
Draw
ItemStruct->rcItem.left + 20, lp
Draw
ItemStruct->rcItem.top + 20, sText); //是否得到焦点 if(lp
Draw
ItemStruct->itemState & ODS_FOCUS) { //画虚框 CRect rtFocus = lp
Draw
ItemStruct->rcItem; rtFocus.DeflateRect(3, 3); dc.
Draw
FocusRect(&rtFocus); } return; } CDialog::On
Draw
Item(nIDCtl, lp
Draw
ItemStruct); } 别忘了标记Owner
draw
属性: 图9 指定按钮的Owner
draw
属性 值得一提的是,CWnd内部截获了WM_
DRAW
ITEM、WM_MEASUREITEM等
消息
,并映射成子元素的相应虚函数的调用,如CButton::
Draw
Item()。所以,以上例子也可以通过派生出一个CButton的派生类,并重载该类的
Draw
Item()函数来实现。使用虚函数机制实现界面美化参见3.4章节。 3.3.5 WM_MEASUREITEM 仅仅WM_
DRAW
ITEM还是不够的,对于一些特殊的
控件
,如ListBox,系统在发送WM_
DRAW
ITEM
消息
前,还发送WM_MEASUREITEM
消息
,需要你设置ListBox中每个项目的高度。 WM_
DRAW
ITEM的映射函数原型如下: afx_msg void OnMeasureItem( int nIDCtl, LPMEASUREITEMSTRUCT lpMeasureItemStruct ); nIDCtl 该
控件
的ID,如果该元素为菜单,则nIDCtl为0 lpMeasureItemStruct指向MEASUREITEMSTRUCT结构对象的指针,MEASUREITEMSTRUCT的结构定义如下: typedef struct tagMEASUREITEMSTRUCT { UINT CtlType; UINT CtlID; UINT itemID; UINT itemWidth; UINT itemHeight; DWORD itemData } MEASUREITEMSTRUCT; CtlType指定了
控件
的类型,其取值如表6所示: 类型值 含义 ODT_COMBOBOX 组合框
控件
ODT_LISTBOX
列表
框
控件
ODT_MENU 菜单项 表6 CtlType的类型值与含义 CtlID 指定自绘
控件
的ID值,该成员不适用于菜单项 itemID表示菜单项ID,也可以表示可变高度的
列表
框或组合框中某项的索引值。该成员不适用于固定高度的
列表
框或组合框。 itemWidth 指定菜单项的宽度 itemHeight指定菜单项或者
列表
框中某项的的高度,最大值为255 itemData 对于菜单项,该成员的取值为由CMenu::AppendMenu、CMenu::InsertMenu、CMenu::ModifyMenu等函数传递给菜单的值。 对于
列表
框或这组合框,该成员的取值为由ComboBox::AddString、CComboBox::InsertString、CListBox::AddString或者CListBox::InsertString等函数传递给
控件
的值。 图示出了OnMeasureItem的效果: 图10 利用WM_MEASUREITEM
消息
美化界面 相应的OnMeasureItem()实现如下: void CUi7Dlg::OnMeasureItem(int nIDCtl, LPMEASUREITEMSTRUCT lpMeasureItemStruct) { if(nIDCtl == IDC_COLOR_PICKER) { //设定高度为 lpMeasureItemStruct->itemHeight = 30; return; } CDialog::OnMeasureItem(nIDCtl, lpMeasureItemStruct); } 同样别忘了指定
列表
框的Owner
draw
属性: 图11 指定下拉框的Owner
draw
属性 3.3.6 NM_CUSTOM
DRAW
大家也许熟悉WM_NOTIFY,
控件
通过WM_NOTIFY向父窗口发送
消息
。在WM_NOTIFY
消息
体中,部分
控件
会发送NM_CUSTOM
DRAW
告诉父窗口自己需要绘图。 可以反射NM_CUSTOM
DRAW
消息
,如: ON_NOTIFY_REFLECT(NM_CUSTOM
DRAW
,
OnCustom
Draw
) afx_msg void
OnCustom
Draw
(NMHDR *pNMHDR, LRESULT *pResult); 参数: pNMHDR 说到底只是一个指针,大多数情况下它指向一个NMHDR结构对象,NMHDR结构如下: typedef struct tagNMHDR { HWND hwndFrom; UINT idFrom; UINT code; } NMHDR; 其中: hwndFrom 发送方
控件
的窗口句柄 idFrom 发送方
控件
的ID code 通知代码 对于某些
控件
来说,pNMHDR则会解释成其它内容更丰富的结构对象的指针,如:对于
列表
控件
来说,pNMHDR常常指向一个NMCUSTOM
DRAW
对象,NMCUSTOM
DRAW
结构如下: typedef struct tagNMCUSTOM
DRAW
INFO { NMHDR hdr; DWORD dw
Draw
Stage; HDC hdc; RECT rc; DWORD dwItemSpec; UINT uItemState; LPARAM lItemlParam; } NMCUSTOM
DRAW
, FAR * LPNMCUSTOM
DRAW
; hdr NMHDR对象 dw
Draw
Stage 当前绘制状态,其取值如表7所示: 类型值 含义 CDDS_POSTERASE 擦除循环结束 CDDS_POSTPAINT 绘制循环结束 CDDS_PREERASE 准备开始擦除循环 CDDS_PREPAINT 准备开始绘制循环 CDDS_ITEM 指定dwItemSpec, uItemState, lItemlParam参数有效 CDDS_ITEMPOSTERASE
列表
项擦除结束 CDDS_ITEMPOSTPAINT
列表
项绘制结束 CDDS_ITEMPREERASE 准备开始
列表
项擦除 CDDS_ITEMPREPAINT 准备开始
列表
项绘制 CDDS_SUBITEM 指定
列表
子项 表7 dw
Draw
Stage的类型值与含义 hdc指定了绘制操作所使用的设备环境。 rc指定了将被绘制的矩形区域。 dwItemSpec
列表
项的索引 uItemState 当前
列表
项的状态,其取值如表8所示: 类型值 含义 CDIS_CHECKED 标记状态。 CDIS_DEFAULT 默认状态。 CDIS_DISABLED 禁止状态。 CDIS_FOCUS 焦点状态。 CDIS_GRAYED 灰化状态。 CDIS_SELECTED 选中状态。 CDIS_HOTLIGHT 热点状态。 CDIS_INDETERMINATE 不定状态。 CDIS_MARKED 标注状态。 表8 uItemState的类型值与含义 lItemlParam 当前
列表
项的绑定数据 pResult 指向状态值的指针,指定系统后续操作,依赖于dw
Draw
Stage: 当dw
Draw
Stage为CDDS_PREPAINT,pResult含义如表9所示: 类型值 含义 CDRF_DODEFAULT 默认操作,即系统在
列表
项绘制循环过程不再发送NM_CUSTOM
DRAW
。 CDRF_NOTIFYITEM
DRAW
指定
列表
项绘制前后发送
消息
。 CDRF_NOTIFYPOSTERASE
列表
项擦除结束时发送
消息
。 CDRF_NOTIFYPOSTPAINT
列表
项绘制结束时发送
消息
。 表9 pResult的类型值与含义(一) 当dw
Draw
Stage为CDDS_ITEMPREPAINT,pResult含义如表10所示: 类型值 含义 CDRF_NEWFONT 指定后续操作采用应用中指定的新字体。 CDRF_NOTIFYSUBITEM
DRAW
列表
子项绘制时发送
消息
。 CDRF_SKIPDEFAULT 系统不必再绘制该子项。 表10 pResult的类型值与含义(二) 以下是一个利用NM_CUSTOM
DRAW
消息
绘制出的多色
列表
框的例子: 图12 利用NM_CUSTOM
DRAW
消息
美化界面 对应代码如下: void CCoolList::
OnCustom
Draw
(NMHDR *pNMHDR, LRESULT *pResult) { //类型安全转换 NMLVCUSTOM
DRAW
* pLVCD = reinterpret_cast
DRAW*>(pNMHDR); *pResult = 0; //指定
列表
项绘制前后发送
消息
if(CDDS_PREPAINT == pLVCD->nmcd.dw
Draw
Stage) { *pResult = CDRF_NOTIFYITEM
DRAW
; } else if(CDDS_ITEMPREPAINT == pLVCD->nmcd.dw
Draw
Stage) { //奇数行 if(pLVCD->nmcd.dwItemSpec % 2) pLVCD->clrTextBk = RGB(255, 255, 128); //偶数行 else pLVCD->clrTextBk = RGB(128, 255, 255); //继续 *pResult = CDRF_DODEFAULT; } } 注意到上例采取了3.1所推荐的第2种实现方法,派生了一个新类CCoolList。 3.4 使用
MFC
类的虚函数机制 修改Windows界面,除了从Windows
消息
机制下功夫,也可以从
MFC
类下功夫,这应该得益于类的虚函数机制。为了防止诸如“面向对象技术”等术语在此泛滥,以下仅举一段代码作为例子: void CView::OnPaint() { // standard paint routine CPaintDC dc(this); OnPrepareDC(&dc); On
Draw
(&dc); } 这是
MFC
中viewcore.cpp中的源代码,很多读者总不明白On
Draw
()和OnPaint()之间的关系,从以上的代码中很容易看出,CView的WM_PAINT
消息
响应函数OnPaint()会自动调用CView::On
Draw
()。而作为开发者的用户,可以通过简单的On
Draw
()的重载实现对WM_PAINT的处理。所以说,对
MFC
类的虚函数的重载是对
消息
机制的扩展。 以下列出了与界面美化相关的虚函数,参数说明略去: CButton::
Draw
Item CCheckListBox::
Draw
Item CComboBox::
Draw
Item CHeaderCtrl::
Draw
Item CListBox::
Draw
Item CMenu::
Draw
Item CStatusBar::
Draw
Item CStatusBarCtrl::
Draw
Item CTabCtrl::
Draw
Item virtual void
Draw
Item( LP
DRAW
ITEMSTRUCT lp
Draw
ItemStruct ); Owner
draw
元素自绘函数 很显然,位图菜单都是通过这个
Draw
Item画出来的。限于篇幅,在此不再附以例程。
MFC
控件
的使用方法(十一(滑块
控件
))
十一、滑块
控件
(Slider Control) 作用:滑动块
控件
”(也称为一个跟踪器)是一个包含一个滑动块和可选的刻度线的窗口。当用户用鼠标或方向键移动滑动块时,该
控件
发送通知
消息
来表明这些改变。当你想要用户选择不连续的值或是某一范围内的连续值的集合时,滑动块
控件
是很有用的。例如,你可以让用户通过移动滑动块到一个给定的刻度线来设置键盘的重复速度。
消息
映射函数: NM_CUSTOMDROW 将自定义绘图操作通知父级 NM_OUTOFMEMORY 指示
控件
由于内存不足而未完成某些工作 NM_REL
如何基于
MFC
的CListCtrl实现虚拟
列表
控件
当我们开发的应用程序中经常用到
MFC
的
列表
控件
来显示数据,但当数据记录超过上千条甚至上万条时,用CListCtrl的一般模式显示效率就有问题:内存占用大,还有刷新时会比较卡。其实CListCtrl还有一个强大的功能--虚拟
列表
模式,这种模式是微软专门为显示大数据量的情况而设计的,比如是数据库的
列表
控件
要显示成千上万条记录,显示效率非常高。工作在这种模式下,数据只在需要显示的时候才被回调,刷...
【
MFC
开发(14)】滑块
控件
Slider Control
Slider滑块
控件
,也是VC中比较常用的一个
控件
。一般而言它是由一个滑动条,一个滑块和可选 刻度组成。用户可以通过移动滑块在相应的
控件
中显示对应的值。通常,在滑动
控件
附近一定有静 态文本框
控件
或编辑框
控件
,用于显示相应的值。 Tick Marks 为是否显示刻度线 Auto Ticks 是否显示每个增量的刻度线 2.
控件
的操作 首先需要给滑动框
添加
一个变量 //设置滑动块的范围 m_slider.SetRange(0, 10); //设置当前的位置 m_slid
界面
15,980
社区成员
115,900
社区内容
发帖
与我相关
我的任务
界面
VC/MFC 界面
复制链接
扫一扫
分享
社区描述
VC/MFC 界面
社区管理员
加入社区
获取链接或二维码
近7日
近30日
至今
加载中
查看更多榜单
社区公告
暂无公告
试试用AI创作助手写篇文章吧
+ 用AI写文章