TN014:自定义控件
此说明描述了 MFC 的自定义和自我绘制控件支持。 它还描述动态 subclassing,并描述 CWnd 对象和 HWNDs. 之间的关系。
MFC 示例应用程序 CTRLTEST 阐释如何使用许多自定义控件。 为 MFC 通用示例 CTRLTEST 和联机帮助查看源代码。
所有者描述控件/菜单
通过使用窗口消息,窗口提供对所有者描述控件和菜单支持。 父窗口所有控件或菜单接收这些消息并调用响应的功能。 您可以重写这些功能自定义您的所有者描述控件或菜单可视外观和行为。
MFC 直接支持具有以下特点的所有者描述:
您可以重写在您的 CWnd 派生类的函数实现自定义绘制行为。
此方法不会导致可重用的代码。 如果您有两个类似的控件在两个不同 CWnd 类,则必须实现自定义控件行为在两个位置。 MFC 支持的自我绘制控件体系结构解决此问题。
自绘制控件和菜单
MFC 提供标准所有者描述消息提供默认实现 (在 CWnd 和 CMenu 类)。 此默认实现会对所有者描述参数和委托所有者描述消息为控件或菜单。 这称为自绘制,因为绘制代码在控件或菜单的类,而不是在所有者窗口。
通过使用自绘制控件可以生成使用所有者描述语义显示控件的可重用控件类。 绘制控件代码在控件类,而不是其父级。 这是一个面向对象的方法来自定义控件编程。 添加下面的列表功能为的自描述类:
使用自我绘制按钮:
CButton:DrawItem(LPDRAWITEMSTRUCT); // insert code to draw this button
使用自我绘制菜单:
CMenu:MeasureItem(LPMEASUREITEMSTRUCT); // insert code to measure the size of an item in this menu CMenu:DrawItem(LPDRAWITEMSTRUCT); // insert code to draw an item in this menu
对于自绘制列表框:
CListBox:MeasureItem(LPMEASUREITEMSTRUCT); // insert code to measure the size of an item in this list box CListBox:DrawItem(LPDRAWITEMSTRUCT); // insert code to draw an item in this list box CListBox:CompareItem(LPCOMPAREITEMSTRUCT); // insert code to compare two items in this list box if LBS_SORT CListBox:DeleteItem(LPDELETEITEMSTRUCT); // insert code to delete an item from this list box
使用自我绘制组合框:
CComboBox:MeasureItem(LPMEASUREITEMSTRUCT); // insert code to measure the size of an item in this combo box CComboBox:DrawItem(LPDRAWITEMSTRUCT); // insert code to draw an item in this combo box CComboBox:CompareItem(LPCOMPAREITEMSTRUCT); // insert code to compare two items in this combo box if CBS_SORT CComboBox:DeleteItem(LPDELETEITEMSTRUCT); // insert code to delete an item from this combo box
有关所有者描述的详细信息结构 (DRAWITEMSTRUCT、 MEASUREITEMSTRUCT、 COMPAREITEMSTRUCT和 DELETEITEMSTRUCT) 为单独 CWnd::OnDrawItem、 CWnd::OnMeasureItem、 CWnd::OnCompareItem和 CWnd::OnDeleteItem 看到 MFC 文档。
使用自我绘制控件和菜单
对于自绘制菜单,必须重写 OnMeasureItem 和 OnDrawItem 方法。
对于自绘制列表框,并且组合框,必须重写 OnMeasureItem 和 OnDrawItem。 必须指定 LBS_OWNERDRAWVARIABLE 样式为列表框或 CBS_OWNERDRAWVARIABLE 字形组合框的在对话框模板。 OWNERDRAWFIXED 样式不会使用自绘制项目,因为具有固定项的高度确定的,自绘制控件附加到列表框之前。 (可以使用方法 CListBox::SetItemHeight 和 CComboBox::SetItemHeight 解决此限制。)
切换到 OWNERDRAWVARIABLE 样式将强制该系统应用 NOINTEGRALHEIGHT 样式应用于控件。 因为控件不能计算与变量指派的项目的集成高度, INTEGRALHEIGHT 默认样式会被忽略,并且该控件始终 NOINTEGRALHEIGHT。 如果您的项目是内置的高度,可以防止分部项目绘制中指定控件大小是项目范围的整数倍数。
对于自我绘制列表框,并具有 LBS_SORT 或 CBS_SORT 样式的,则组合框必须重写 OnCompareItem 方法。
对于自我绘制列表框,并且组合框, OnDeleteItem 通常未被重写。 ,如果要执行任何特殊处理,可以重写 OnDeleteItem 。 这适用的一种情况是更多的内存或其他资源存储到每个列表框或组合框项。
自我绘制控件和菜单的示例
MFC 通用示例 CTRLTEST 提供自绘制菜单的示例,并自绘制列表框。
自我绘制按钮的最典型的示例是位图按钮。 位图按钮是显示不同状态的一个,两个或三个位图图像的按钮。 此示例在 MFC 类 CBitmapButton提供。
动态 Subclassing
有时您会希望更改已存在对象的功能。 ,在创建之前,上一示例要求您自定义控件。 动态 subclassing 可以自定义已创建的控件。
Subclassing 是替换 " 窗口的 WndProc 具有自定义的 WndProc 和调用的早期 WndProc 窗口术语默认功能。
不应使用 C++ 类派生混淆。 有关说明, C++ 术语 基类 和 派生类 类似于 创建超类时 和 子类 在窗口对象模型。 与 MFC 的 C++ subclassing 派生和窗口在功能上是等效的,因此,只不过 C++ 不支持动态 subclassing。
CWnd 类提供 c. C++ 对象 (从派生 CWnd) 和窗口对象之间的连接 (称为的 HWND)。
这些相关的有三种常见方法:
CWnd 创建 HWND。 可以通过创建从 CWnd派生的类修改在派生类的行为。 ,当应用程序调用 CWnd::Create时, HWND 创建。
应用程序附加 CWnd 到现有 HWND。 不修改现有窗口的行为。 这是一种情况下委托和通过调用别名的 CWnd::Attach 可以对 CWnd 对象的现有 HWND 。
CWnd 附加到现有 HWND ,还可以更改在派生类的行为。 这称为动态 subclassing,因为我们将更改行为,而类,在运行时将窗口对象。
使用方法 CWnd::SubclassWindow 和CWnd::SubclassDlgItem,您可实现动态 subclassing。
两个实例附加到现有 HWND的一 CWnd 对象。 SubclassWindow 直接执行 HWND 。 SubclassDlgItem 是采用控件 ID 和父窗口的 helper 函数。 SubclassDlgItem 为附加到从对话框模板创建的对话框控件的 C++ 对象模型。
在参见 CTRLTEST 示例进行的几个示例中使用 SubclassWindow 和 SubclassDlgItem。