标准控件的使用技巧与自绘控件的优缺点,简述如何自定义控件

  标准控件的使用技巧与自绘控件的优缺点,简述如何自定义控件

  当您决定在Windows提供的传统免费自定义控件的范围之外开发控件时,您必须确定您的控件在功能和外观上有多独特。例如,假设您正在创建一个类似于速度计的控件。由于公共控件库(ComCtrl32.dll)中没有类似的控件,所以需要自己完成以下工作:编写控件所有功能所需的代码,绘制它,默认最终用户的交互,处理控件与其父窗口之间的任何消息。

  (#补充两个方面,公共控件库中没有类似的完全重写;如果只想调整公共控制功能,可以部分修改)。

  另一方面也包括一些你只想调整常用控件功能的情况。例如,假设您想要创建一个屏蔽编辑控件,它只允许接受指定的字符。如果使用MFC,通常涉及从MFC提供的类派生一个类,封装一个公共控件(通常是屏蔽编辑控件中的CEdit),重写必要的虚函数(或者处理指定的消息),然后添加自定义代码。

  本文的重点在两者之间——公共控件提供了您想要的大部分功能,但是控件的外观并不是您想要的。例如,列表视图控件提供了一种以多种视图样式(小图标、大图标、列表和详细列表(报告))显示数据列表的方法。但是,如果你想要一个网格控件,结果是什么呢?虽然公共控件库没有特别包含网格,但是列表视图控件与它很接近。它按行和列显示数据,并有一个关联的标题控件。因此,许多人从一个标准的列表视图控件开始创建自己的网格控件,然后重写该控件及其子控件的呈现或绘制方法。

  即使你“仅仅”绘画,你仍然至少有四种选择,它们都有明显的优点和缺点:

  处理WM _ paint、所有者绘图、自定义绘图和WM_CTLCOLOR。

  处理WM_PAINT

  最极端的选择是执行WM_PAINT处理程序,自己完成所有的绘制工作。这意味着您的代码将需要做一些与呈现控件相关的琐碎事情—创建适当的设备上下文、决定控件的大小和位置、绘制控件等。在绘图的过程中,很少需要这种程度的控制。

  业主图纸

  控制控件绘制的另一种方法是由所有者绘制。事实上,您可能听过开发人员提到所有者描述控件,因为这是开发自定义控件最常用的技术。这项技术被广泛使用的主要原因是Windows可以给你提供很多帮助。在渲染控件的时刻,Windows已经创建并填充了设备上下文,确定了控件的大小和位置,并给你发送了信息,让你知道此时的绘制要求。对于列表控件(例如列表框和列表视图),Windows会为列表中的每一项调用draw代码,也就是说你只需要绘制这些项,而不需要考虑控件的其他方面。请注意,所有者描述可用于大多数控件。但是,它不能用于编辑控件;而且考虑到列表控件,只能用在报表视图风格。

  自定义绘图

  这可能是绘制自己的控件最不为人知的技术。事实上,很多技术能力很高的开发者也混淆了自绘和定制这两个术语。首先我们要知道自定义控件只针对指定的公共控件:表头、列表视图、rebar、工具栏、工具提示、跟踪栏、树形视图。此外,虽然所有者描述只允许用报表视图样式绘制列表视图控件,但自定义描述使您能够处理列表视图控件的所有视图样式的绘制。使用自定义绘图的另一个明显的优点是,您可以严格选择您想要绘制的内容。这是通过Windows在控件绘制的每个阶段向代码发送一条消息来实现的。这样,您可以决定是否在每个阶段自己完成所有绘图工作,增加默认绘图,或者允许Windows执行该阶段的所有绘图。(由于自定义绘图是本文的主题,您将很快看到它是如何工作的。)

  处理WM_CTLCOLOR消息

  这可能是帮助决定如何呈现控件的最简单的方法。如消息名所示,当要绘制一个控件,并且它能让你的代码决定使用哪种画笔时,发送WM_CTLCOLOR消息(#add好像不对,应该是消息反映的)。通常,如果您只想更改控件的颜色(#addSetTextColor SetBkColor),并且不提供比控件本身更多的功能,则使用这种技术。另外,对于公共控件(列表视图、树形视图、rebar等。)由Internet Explorer引入,不发送此消息,它只与标准控件(编辑、列表框等)结合使用。).

  CTLCOLOR _静态静态控制

  BTN按钮控件

  CTLCOLOR_EDIT编辑控件

  CTLCOLOR_LISTBOX列表框控件

  CTLCOLOR_SCROLLBAR滚动条控件

  CTLCOLOR_DLG对话框

  CTLCOLOR_MSGBOX消息框

  对于组合框中的下拉列表框不会调用OnCtlColor函数,因为下拉列表框实际上是组合框的子窗口,而不是窗口的子窗口。要更改下拉列表框的颜色,请创建一个CComboBox,并在重载OnCtlColor的nCtlColor参数中选中CTLCOLOR_LISTBOX。在这个处理函数中,必须使用SetBkColor成员函数来设置文本的背景。

  自定义绘图:

  现在您已经知道了绘图控件的各种可用选项(包括使用自定义绘图的好处),让我们来看看实现自定义绘图控件所需的三个主要步骤。

  执行NM_CUSTOMDRAW消息处理程序。指定处理所需的绘图阶段。筛选特定的绘制阶段(在这些阶段中,您需要添加自己的特定于控件的绘制代码)。

  1,执行一个NM_CUSTOMDRAW消息处理程序。

  当需要绘制一个公共控件时,MFC会将控件的自定义绘制通知消息(最初发送给控件的父窗口)以NM_CUSTOMDRAW消息的形式反馈给控件。以下是NM_CUSTOMDRAW处理程序的示例。

  void CMyCustomDrawControl:OnCustomDraw(NMHDR * pnm HDR,LRESULT * pResult){ LPNMCUSTOMDRAW pnm CD=reinterpret _ cast(pnm HDR);}

  如您所见,NM_CUSTOMDRAW处理程序传递了一个指向NMHDR类型结构的指针。但是,这个值对于NMHDR这样只有三个成员(hwndFrom、idFrom和code)的结构来说是不够的。

  因此,通常需要将结构指针转换成包含更多信息的结构—LPNMCUSTOMDRAW。LpcustomDraw指向NMCUSTOMDRAW,它包含诸如dwDrawStage、dwItemSpec和uItemState之类的成员,这些成员是确定当前绘图阶段和确切绘图(例如,控件本身,或者控件的项或子项)所必需的。

  这里值得注意的是,还可以将NMHDR指针指向特定于所绘制的控件类型的结构。表1显示了控件及其关联的自定义绘图结构类型名称的列表。

  表1:控件及其相关的自定义绘图结构

  钢筋,跟踪栏,认证票,我的。资源,我的。设置,我的。用户和My.WebServices

  2.指定处理所需的绘图阶段。

  正如我前面提到的,绘制控件有一些“阶段”。特别是,您可以将绘制过程理解为一系列阶段,在这些阶段中,控件通知其父窗口需要绘制的内容。事实上,控件甚至会在绘制控件及其项之前和之后发送通知,以便程序员更好地控制该过程。

  在所有情况下,在每个绘制阶段都会调用一个NM_CUSTOMDRAW处理程序。但是,请记住:自定义绘图允许您将默认的控件绘图合并到您自己的绘图中,并且您需要指定您将处理哪个绘图阶段。这是通过设置NM_CUSTOMDRAW处理程序的第二个参数(pResult)来完成的。其实如果你从来不设置这个值,在初始阶段用CDDS_PREPAINT调用函数后,你的函数就不再被调用了!

  从技术上讲,只有两个阶段指定了所需的绘制阶段(CDDS_PREPAINT和CDDS_ITEMPREPAINT),这两个阶段会影响发送通知消息的内容。但是,通常只在处理程序的末尾指定代码将处理的绘制阶段。表2列出了用于指定所需绘制阶段的值(这是代码关注的重点)。

  表2:自定义绘图返回标志

  下面是一个示例,其中的代码指定在绘制控件的项(CDRF_NOTIFYITEMDRAW)和子项(CDRF_NOTIFYPOSTPAINT)并完成绘制时,应调用NM_CUSTOMDRAW处理程序。

  void CListCtrlWithCustomDraw:OnNMCustomdraw(NMHDR * pnm HDR,LRESULT * pResult){ LPNMCUSTOMDRAW pnm CD=reinterpret _ cast(pnm HDR);* pResult=0;//初始化value * pResult =CDRF _ NOTIFYITEMDRAW;* pResult =CDRF _ notify subitedraw;* pResult =CDRF _ NOTIFYPOSTPAINT;}

  3.筛选指定的绘图阶段。

  一旦你指定了要关注的阶段,你就需要处理它们。因为在绘制过程的每个阶段只有一条消息要发送,所以通常执行switch语句来确定确切的绘制阶段。的不同绘制阶段由以下标志定义:

  CDDS _ PREPAINT CDDS _ ITEM CDDS _ ITEM PREPAINT CDDS _ ITEM post paint CDDS _ ITEM PREERASE CDDS _ ITEM POSTERASE CDDS _子项CDDS _ post paint CDDS _ PREERASE CDDS _ POSTERASE

  对于从CListCtrl派生的类,有一个NM_CUSTOMDRAW处理程序的例子,在这个例子中你可以发现代码决定了当前绘制阶段的方式:

  void CMyCustomDrawControl:OnCustomDraw(NMHDR * pnm HDR,LRESULT * pResult){ LPNMCUSTOMDRAW pnm CD=reinterpret _ cast(pnm HDR);switch(pnm CD-dwDrawStage){ case CDDS _ PREPAINT:打破;案例CDDS_ITEMPREPAINT:打破;案例CDDS_ITEMPREPAINT CDDS_SUBITEM:打破;} * pResult=0;}

  注意,为了确定子项(例如列表视图控件)的绘制阶段,必须使用按位or运算符,该运算符有两个值:一个是CDDS_ITEMPREPAINT或CDDS _ Itemstopaint,另一个是CDDS _子项。

  为了说明这一点,让我们假设您想在绘制列表视图项目之前做一些处理。编写一个switch语句来处理CDDS_ITEMPREPAINT。

  案例CDDS_ITEMPREPAINT:打破;

  但是,如果是相关子项的预绘图阶段,您将执行以下操作:

  案例CDDS_ITEMPREPAINT CDDS_SUBITEM:打破;

  示例:创建一个列表视图控件自定义绘图控件

  如前所述,您可以完全控制控件及其项的绘制,或者只执行少量特定于应用程序的绘制,并让控件继续。本文的重点是控制绘图技术,而不是高级绘图技术。我们将浏览一个简单的示例,其中列表视图控件是一个自定义绘图,因此项目的文本将在创建拼接外观的交替单元格中以不同的颜色显示。

  创建一个基于Visual C 2005对话框的项目,命名为ListCtrlColor。

  从“类视图”中选择“项目”菜单选项,然后单击“添加类”以调用“添加类”对话框。

  从分类列表中选择MFC,然后从模板列表中选择MFC类。

  单击“添加”按钮调用“MFC类向导”对话框。

  对于类名,键入值CListCtrlWithCustomDraw,并选择CListCtrl的基类。

  单击Finish按钮生成类头和可执行文件。

  对于“类视图”,右击CListCtrlWithCustomDraw类并选择“属性”上下文菜单选项。

  当显示“属性”窗口时,单击顶部的“消息”按钮以显示两列消息列表,您可以为其实现处理程序。

  单击消息列表中的NM_CUSTOMDRAW项,然后下拉第二列中的组合框箭头,并选择OnNMCustomdraw值。

  现在,处理绘图代码。这里我们简单处理一下项和子项的预绘制阶段,根据当前行(项)和列(子项)指定文本和背景色。为此,请修改OnNMCustomdraw函数,如下所示:

  void CListCtrlWithCustomDraw:OnNMCustomdraw(NMHDR * pnm HDR,LRESULT * pResult){ LPNMLVCUSTOMDRAW lpLVCustomDraw=reinterpret _ cast(pnm HDR);switch(lpLVCustomDraw-nmcd . dwdraw stage){ case CDDS _ item prepaint:case CDDS _ item prepaint CDDS _ SUBITEM:if(0==((lpLVCustomDraw-nmcd . dwitemspec lpLVCustomDraw-iSubItem)% 2)){ lpLVCustomDraw-clr text=RGB(255,255,255);//white text lpLVCustomDraw-clrTextBk=RGB(0,0,0);//黑色背景} else { lpLVCustomDraw-CLR text=CLR _ DEFAULT;lpLVCustomDraw-clrTextBk=CLR _ DEFAULT;}破;默认:break} * pResult=0;* pResult =CDRF _ NOTIFYPOSTPAINT;* pResult =CDRF _ NOTIFYITEMDRAW;* pResult =CDRF _ notify subitedraw;}

  现在,让我们测试新的控件。为此,只需使用CListCtrlWithCustomDraw类将列表视图控件放置在对话框中,并对其进行子类化。下面是完成这个操作的步骤。

  在资源视图中,打开应用程序的主对话框(IDD_LISTCTRLCOLOR_DIALOG)。

  从工具箱中,将列表控件拖放到对话框中。

  右击列表控件并选择属性上下文菜单选项。

  将视图属性设置为报告。

  右键单击控件并选择“添加变量”上下文菜单选项。

  在“添加成员变量向导”对话框中,指定变量名m_lstBooks,然后单击“完成”按钮。

  此时,您有了一个CListCtrl派生类(m_lstBooks),它对对话框上的列表视图控件进行了子类化。但是,m_lstBooks需要从新创建的CListCtrlWithCustomDraw派生,以便调用您的绘图代码。因此,打开对话框的标题文件(ListCtrlColorDlg.h),将m_lstBooks更改为CListCtrlWithCustomDraw类型。

  在CListCtrlColorDlg类开始之前添加以下指令。

  # include " listctrlwithcustomdraw . h "

  将下面的代码添加到对话框的OnInitDialog成员函数中,这样我们可以看到一些列表视图行。

  //插入列m_lstBooks。InsertColumn(0,_ T( Author ));m_lstBooks。InsertColumn(1,_ T( Book ));//定义数据静态结构{ TCHAR m _ SZ author[50];TCHAR m _ SZ title[100];} BOOK_INFO[]={ _T(Tom Archer ),_T(Visual C .NET圣经),_T(Tom Archer ),_T(用。NET Framework )、_T(布莱恩约翰逊)、_ T( XBox 360 For Dummies )};//插入数据int idxfor(int I=0;I sizeof BOOK _ INFO/sizeof BOOK _ INFO[0];i ) { idx=m_lstBooks。InsertItem(i,BOOK_INFO[i]。m _ SZ author);m_lstBooks。SetItemText(i,1,BOOK_INFO[i].m _ SZ title);}

  现在,构建并运行应用程序。图1显示了应用程序外观的一个例子。

  图一。自定义绘图示例应用程序

  总结

  当Windows作为“下一代”操作系统首次引入应用程序开发时,其新的图形用户界面的一个主要论点是它的一致性。这个论点的要点是它有一个共同的外观:统一的菜单项,共同的控件等。这种普遍性的感觉可能会持续下去,直到第二家公司想要设计自己的应用程序。简单来说,没有一家公司会通过提供看起来和其他应用相似的应用来逃离这个怪圈。

  构建独特且令人难忘的用户界面的一种方法是为应用程序设计和开发自定义控件。希望这篇文章能帮到你。现在,你知道了一个非常强大的技术,让你的应用从众多竞争对手的应用中脱颖而出。

  OWNER DRAW实现了自绘制按钮。

  一.准备工作

  在开始编码之前,您应该首先确定,或者更准确地说,设计按钮在各种状态下的外观。按钮的几种基本状态包括:

  正常状态是按钮第一次显示时的样子。

  悬停状态,鼠标指针移动到按钮上时按钮的显示方式。

  按下状态,按钮按下时的样子。

  焦点状态,按钮被按下和释放的方式。例如,当按下并释放标准按钮时,您会在按钮内看到一个虚线框。

  当然,禁用状态是按钮被设置为无效时的样子。

  我参考了WindowsXP中普通按钮的实际外观,设计了XP按钮各种状态的外观,如下图所示:

  至于按下状态,主要是在Over状态的基础上把文字稍微向右下方偏移,达到按下的效果。

  二、实现原理和难点

  让我们开始创建类。在Workspace的ClassView页面中,右键单击列表树的根节点,然后选择New Class…

  在弹出窗口中定义派生类,如下图所示。注意,您只需要填写两项,Name和Base class,其余选项可以保留默认值。

  下面简单介绍一下按钮的实现原理:

  1.初始化控件时,为按钮添加Owner Draw的属性。这是因为在MFC中,为了激活控件的自绘功能,要求控件的属性必须包含属性值BS_OWNERDRAW。这一步我们可以通过类向导将PreSubclassWindow()函数添加到CXPButton类中,完成该函数中属性值的设置。当控件的自绘制功能被激活时,每次控件的状态发生变化都会运行DrawItem()函数,它的作用是绘制控件在各种状态下的外观。

  2.添加WM_MOUSELEAVE消息函数,当鼠标指针离开按钮时触发。我们在函数中添加代码,通知DrawItem函数鼠标指针已经离开,并让按钮重画。

  3.添加WM_MOUSEHOVER消息函数。当鼠标指针在按钮上时,该消息功能将被触发。我们向函数中重新添加代码,通知DrawItem函数鼠标指针现在位于按钮上,并让按钮重绘。

  4.添加DrawItem函数。根据按钮在DrawItem中的当前状态绘制按钮的外观。可以说自绘控件的大部分功能都是在这个函数中实现的。DrawItem函数包含一个指向LPDRAWITEMSTRUCT的指针,这将在本文后面解释。

  这里有两个困难。首先,WM_MOUSELEAVE和WM_MOUSEHOVER不是标准的Windows消息函数,不能通过类向导添加。所有的添加工作都需要通过手动输入代码来完成。另一个难点是DrawItem中的指针LPDRAWITEMSTRUCT,它指向DRAWITEMSTRUCT的一个结构,这个结构包含了控件的各种细节,为我们提供了实现自绘功能所必需的信息。

  难点一:

  实际上,两个Windows消息WM_MOUSELEAVE和WM_MOUSEHOVER都是由WM_MOUSEMOVE消息触发的,WM_MOUSEMOVE是标准的Windows消息,所以我们可以通过类向导将WM_MOUSEMOVE消息函数添加到CXPButton类中。

  该函数的代码如下所示。这段代码非常有用。在其他自画控件中,如果要触发WM_MOUSELEAVE和WM_MOUSEHOVER消息,也是通过类似的方法实现的。

  void cxp button:OnMouseMove(UINT nFlags,CPoint)

  {

  //TODO:在此添加您的消息处理程序代码和/或调用default

  如果(!移动跟踪)

  {

  TRACKMOUSEEVENT tme

  tme . CB size=sizeof(tme);

  tme.hwndTrack=m _ hWnd

  tme . dw flags=TME _离开 TME _哈弗;

  tme . dwhover time=1;

  m _ b tracking=_ track mouse event(tme);

  }

  CButton:OnMouseMove(nFlags,point);

  }

  然后我们添加WM_MOUSELEAVE和WM_MOUSEHOVER消息函数。在CXPButton类的声明中(即XPButton.h文件中),找到afx _ msg void onm ousemove(uintnflags,cpointpoint);的函数声明,以及紧接在它下面的输入

  afx _ msgLRESULT onm ouseLeave(WPARAM WPARAM,LPARAM LPARAM);

  afx _ msgLRESULT onm ouseHover(WPARAM WPARAM,LPARAM LPARAM);

  然后在XPButton.cpp文件中找到ON_WM_MOUSEMOVE(),然后输入。

  ON_MESSAGE(WM_MOUSELEAVE,OnMouseLeave)

  ON_MESSAGE(WM_MOUSEHOVER,OnMouseHover)

  难点二:

  我们来看看draw items休战结构给我们提供了哪些有用的信息。

  DRAWITEMSTRUCT结构定义如下:

  typedefstruct tagDRAWITEMSTRUCT

  {

  UINT CtlType//控件类型

  UINT CtlID//控件ID

  UINT itemID//菜单项、列表框或组合框中项的索引值

  UINT itemAction//控制行为

  UINT itemState//控制状态

  HWND hwndItem//父窗口句柄或菜单句柄

  HDC hDC//对应于控件的绘图设备的句柄

  RECT rcItem;//控件占据的矩形区域

  DWORD itemData//列表框或组合框中项的值

  }DRAWITEMSTRUCT,*PDRAWITEMSTRUCT,* LPDRAWITEMSTRUCT

  其实不仅仅是按钮控件,其他控件也有,比如ComboBox,ListBox,StaticText等。通过DRAWITEMSTRUCT记录控制信息。有关此结构的详细文档,请参考本文的附录。

  也许你已经看过很多自绘按钮的例子了。其实自绘按钮的函数结构都差不多,其显示效果的差异主要取决于代码编写人员对GDI绘图函数的应用和掌握。有兴趣的朋友可以研究一下CXPButton类中DrawItem函数的数据结构。其实只要修改GDI画图函数的一些代码,马上就可以再做一个自画图按钮控件。

  第三,按钮类的使用

  下面演示CXPButton类的用法。向对话框中添加一个按钮控件,假设其ID值为IDC_BUTTON1。进入类向导的成员变量属性页,为IDC_BUTTON1添加一个变量m_btnNormal。点击确定,然后编译,就可以看到重新定义了XP风格的按钮。

  如果将CXPButton的源文件导入到自己的项目中,就看不到上图中变量类型中的CXPButton选项了。但可以通过以下方法添加:

  1.首先保存项目,然后退出。

  2.查找带有后缀的文件。clw并删除它。但为了以防万一,我建议你做个备份。

  3.重新打开项目并进入类向导。这时,你会看到一个弹出的对话框。我们选择“是”。

  4.再次选择“Add All ”,这样我们就可以在类向导中使用CXPButton的变量类型。

  四。总结和提示

  对于一个按钮,当按钮的任何可见部分改变时,调用DrawItem函数来重画它。自绘按钮必须设置BS_OWNERDRAW的属性,设置代码在PreSubclassWindows函数中完成。另外,为了防止系统字体设置的改变影响控件的表达效果,还可以在该函数中为控件指定一个固定的字体。但是要注意这个。

  我们来回顾一下实现自绘按钮的基本步骤:

  A.确定设计方案;

  B.初始化,但是记得在函数退出之前,恢复之前的GDI对象,释放占用的资源;

  C.增加相应消息功能;

  D.添加绘图函数DrawItem。DrawItem中的绘制顺序一般是先画外边框,再画背景色,再写文字,最后画内边框。不过也有人喜欢在最后画边框,问题不大。

  动词(verb的缩写)附录

  DRAWITEMSTRUCT结构文档(根据Msdn翻译)

  DRAWITEMSTRUCT

  DRAWITEMSTRUCT为需要自绘的控件或菜单项提供必要的信息。获取WM_DRAWITEM消息函数中对应于要绘制的控件或菜单项的结构的指针。DRAWITEMSTRUCT结构定义如下:

  typedef struct tagDRAWITEMSTRUCT

  {

  UINTCtlType

  UINTCtlID

  UINTitemID

  UINTitemAction

  UINTitemState

  HWNDhwndItem

  HDC hDC

  RECTrcItem

  ULONG _ PTRitemData

  } DRAWITEMSTRUCT

  成员:

  CtlType

  指定控件的类型,其值如下表所示。

  模块

  指示菜单项ID,或列表框或组合框中项的索引值。对于空列表框或组合框,该成员的值为1。此时,应用程序只绘制焦点矩形(该矩形的坐标由rcItem成员给出)。虽然此时控件中没有要显示的项,但绘制焦点矩形是必要的,因为它可以提示用户控件是否有输入焦点。当然,也可以将itemAction成员设置为适当的值,这样就不需要绘制焦点了。

  项目操作

  指定绘制行为,其值可以是下表中显示的一个或多个值的组合。

  如果控件获得或失去焦点时需要绘制,请设置此值。此时,应检查itemState成员以确定控件是否具有输入焦点。

  如果在选定状态改变时需要绘制控件,请设置此值。此时,应检查itemState成员以确定控件是否被选中。

  项目状态

  指定当前绘制操作完成后绘制项的可见状态。例如,如果菜单项应该是灰色的,您可以指定ODS_GRAYED状态标志。它的值可以是下表中显示的一个或多个值的组合。

  Windows 98/Me、Windows 2000/XP:如果鼠标指针在控件上,则设置该值,然后控件将显示突出显示的颜色。

  hwndItem

  指定组合框、列表框、按钮等自画控件的窗口句柄。如果自绘对象是菜单项,则意味着包含该菜单项的菜单句柄。

  陡坡缓降控制系统

  指定用于绘制操作的设备环境。

  rcItem

  指定要绘制的矩形区域。这个矩形区域就是上面hDC的范围。系统会自动裁剪控件的部分,如组合框、列表框或按钮在自绘区域之外的部分。也就是说rcItem中的坐标点(0,0)是指控件的左上角。但是系统并没有裁剪出菜单项,所以在绘制菜单项时,我们首先要通过一定的转换得到菜单项的位置,以保证绘制操作在想要的区域进行。

  数据

  对于菜单项,此成员的值可以通过以下方式确定

  CMenu:AppendMenu,

  Cmu:插入菜单或

  CMenu:ModifyMenu

  等待函数传递给菜单的值。

  对于列表框或组合框,该成员的值可以是

  ComboBox:AddString,

  ccombox:insert string,

  CListBox:添加字符串或

  CListBox:InsertString

  等待传递给控件的值。

  如果ctlType的值为ODT _按钮或ODT _静态,则itemdata的值为0。

  出发地:http://blog..net/weiqubo/article/details/6832566

标准控件的使用技巧与自绘控件的优缺点,简述如何自定义控件