CTRLTEST 示例:实现自定义控件

更新:2007 年 11 月

CTRLTEST 示例阐释若干用于实现和使用自定义控件的技术:

  • 实现 CParsedEdit(一个从其库控件类派生功能的专用编辑控件)和三种使用自定义控件的方法。

  • 使用数值调节钮控件 (Spin Control)。数值调节钮控件 (Spin Control) 包含用于递增或递减值的向上箭头和向下箭头小按钮。

  • 使用 CBitmapButton 实现“Custom”菜单命令的位图按钮。

  • 菜单和列表框的所有者(父窗口)绘制。从 CMenu 类和 CListBox 派生的相应控件类以面向对象的方式提供此功能。

  • 使用 Microsoft Visual C++ 资源编辑器无法维护的资源文件。这阐释了在包含一个自定义控件(其样式由头文件中的常数定义)的对话框中使用 .rc2 文件的优点和缺点。

CTRLTEST 中的所有示例都通过菜单命令启动。

安全说明:

提供该示例代码是为了阐释一个概念,并不代表着最安全的编码实践,因此不应在应用程序或网站中使用该示例代码。对于超出本示例代码的预期用途以外的使用所造成的偶然或继发性损失,Microsoft 不承担任何责任。

获取示例和安装示例的说明:

  • 在 Visual Studio 的“帮助”菜单上,单击“示例”。

    有关更多信息,请参见定位示例文件

  • 示例的最新版本和完整列表可以从 Visual Studio 2008 Samples page(Visual Studio 2008 示例页面)联机获取。

  • 还可以在计算机的硬盘上查找示例。默认情况下,示例和自述文件将复制到 \Program Files\Visual Studio 9.0\Samples\ 下的文件夹中。对于 Visual Studio 速成版,所有示例都位于联机位置。

生成并运行示例

生成并运行 CTRLTEST 示例

  1. 打开解决方案 Ctrltest.sln。

  2. 在“生成”菜单中单击“生成”。

  3. 在“调试”菜单中,单击“开始执行(不调试)”。

示例:实现和使用自定义控件

可通过从 CWnd 派生来实现自定义控件,但如果可以通过从标准 Windows 控件在库中的控件类派生来借用它的功能,则要容易得多。CTRLTEST 以这种方法实现专用编辑控件 CParsedEdit。此编辑控件只接受指定的字符集(数字、字母或非控制字符)作为用户输入。CParsedEditCEdit 派生。它包含一个用于筛选字符的 OnChar 消息处理程序。

“Simple”菜单命令的实现阐释了三种使用自定义控件的方法。这些方法按照应用程序将对话框中的控件实例与 CParsedEdit 类关联的方式加以区分。每个“Simple”菜单命令均显示一个包含四个 CParsedEdit 控件实例的对话框。在该对话框中输入的数据作为 TRACE 输出发送到调试端口。三个“Simple”菜单命令是:

Test C++ Derived Class

这些 CParsedEdit 控件是对话框类的数据成员。这些控件是通过调用 CParsedEdit::CreateSet 在对话框的 OnInitDialog 函数中显式创建的。请参见 Dertest.cpp。

Test WNDCLASS Registered

这些 CParsedEdit 控件在对话框模板资源 (IDD_WNDCLASS_EDIT) 中被布置成带有标识为“paredit”的 WNDCLASS 的自定义控件。使用 Visual C++ 对话框编辑器检查这些自定义控件的属性是有益的。

  • Caption blank。这是 CParsedEdit 控件中显示的初始值。

  • Class:paredit。这是在调用对话框之前,由 CParsedEdit::RegisterControlClass 在 PAREDIT2.CPP 中注册的 WNDCLASS 名称。

  • Visible:checked。控件可见。

  • Tabstop:checked。用户可以使用 Tab 键移动到此控件。

  • 样式 0x5081002、0x5081001、0x5081003、0x5081ffff 用于四个分析编辑控件。样式 0x500000 用于 WS_CHILD 和 WS_VISIBLE,0x1000 用于 WS_TABSTOP。所有自定义控件都有 WS_CHILD 样式。当您选中 Visible 和 Tabstop 样式时,对话框编辑器自动设置 WS_VISIBLE 和 WS_TABSTOP 样式。0x80000 用于 WS_BORDER。由于自定义控件的对话框编辑器属性页确实提供所有窗口样式(如 WS_BORDER),因此必须在 \Microsoft Visual Studio .NET 2003\Vc7\PlatformSDK\Include\WINUSER.H 中查找常数。样式 0x0001、0x0002、0x0004 和 0x0ffff 在 PAREDIT.H 中分别定义为 PES_NUMBERS、PES_LETTERS、PER_OTHERCHARS 和 PES_ALL。

  • 自定义控件属性页中的十六进制样式不自记录。如果使用符号样式(如 PES_NUMBERS 和 PES_LETTERS)对您很重要,您也可以手动编辑一个单独的资源文件(如 RES\Ctrltest.rc2),资源编译器在编译时包括该文件,但 Visual C++ 在编辑时不读取它。有关在 .rc2 文件中手动编辑自定义控件对话框的优缺点的讨论,请参见 使用 Visual C++ 资源编辑器无法维护的资源文件。

测试动态子类

这些控件在对话框模板资源(Ctrltest.rc 中的 IDD_SUB_EDIT)中被布置成标准编辑控件。控件在对话框类中被声明为 CParsedEdit 数据成员。对话框的 OnInitDialog 函数调用 CParsedEdit::SubClassEdit,后者接着调用 CWnd::SubclassDlgItem,以将编辑控件的每个特定实例与 CParsedEdit 类关联。请参见 Paredit.cpp。

示例:数值调节钮控件 (Spin Control)

CTRLTEST 示例包含数值调节钮控件的实现。数值调节钮控件包含用于递增或递减值的向上箭头和向下箭头小按钮。

Spin Control 命令调用一个包含四个 CParsedEdit 控件(每个与一个数值调节钮控件关联)的对话框。筛选在此对话框的 CParsedEdit 控件中输入的数据,从而只接受非负整数。用户可以通过向 CParsedEdit 控件中键入值或使用关联的数值调节钮控件来输入数值数据。

示例:位图按钮

下列“Custom”菜单命令的实现阐释了 CBitmapButton 的用法:

  • “Bitmap Button 1”- 此对话框构造函数通过调用 CBitmapButton::LoadBitmaps,为按钮的三种状态(向上、向下和焦点)的每一种显式加载位图资源。

  • “Bitmap Button 2”- 此对话框的 OnInitDialog 函数调用 CBitmapButton::Autoload 以根据下列命名规则加载位图资源。控件的窗口文本充当基资源名称,并追加字母 U、D 和 F,来创建三个位图图像(分别为向上、向下和焦点)的每一个的资源名称。例如,“确定”按钮的三个位图资源的名称是 OKU、OKD 和 OKF。

  • “Bitmap Button 3”- 此对话框是上面第二个对话框的扩展,它使用第四个可能的按钮状态:禁用。若要使用此对话框,请单击向左或向右箭头位图按钮,直到显示的数字到达最小数 1 或最大数 10。到达限制值时,按钮将被禁用并显示第四个位图图像。禁用状态的位图资源命名规则是以 X 为后缀,如资源名称 PREVX 和 NEXTX 所反映的那样。

示例:所有者描述(菜单和列表框)

各种 Windows 控件和菜单不是采用标准控件行为,而是具有所有者描述功能,允许父(或所有者)窗口在控件的工作区随意进行绘制。相应的控件类和 CMenu 类以更方便的、面向对象的方式提供此功能,即由控件或菜单类处理绘制。这称为“自我绘制”。

CTRLTEST 阐释了在实现下列“Custom”菜单命令时使用的常规所有者描述方法:

  • “Custom Menu”- 此菜单项调用从 CMenu 派生的 CColorMenu 弹出菜单。每个子菜单项使用自我绘制功能显示八种颜色之一。消息框确认从子菜单中选择的颜色。

  • “Custom List Box”- 此菜单项调用一个对话框,该对话框显示从 CListBox 派生的 CColorListBox。该列表框包含八项,每项使用自我绘制功能以八种颜色之一绘制。TRACE 输出确认从该列表框中选择的颜色。

示例:使用 Visual C++ 资源编辑器无法维护的资源文件

资源文件 CTRLTEST\RES\Ctrltest.rc2 是 Visual C++ 资源编辑器无法以可读形式维护的资源文件的一个示例。如果在 Visual C++ 中打开 Ctrltest.rc2 然后保存它,则会丢失有用的可读信息,即使资源编译器仍能够编译 .rc2 文件并生成等效的二进制 .res 文件。因此,已使用 Resource File Set Includes 命令指定的编译时指令在 Ctrltest.rc 中将 RES\Ctrltest.rc2 添加为 #include。

以下是三类 Visual C++ 资源编辑器无法维护的可读信息。Ctrltest.rc2 说明了其中的两类:

  • 自定义控件样式符号 — 例如,“msctls_updown32”是为数值调节钮控件定义的样式。尽管 Visual C++ 在读取 .rc2 文件时可以解释此符号,但 Visual C++ 将以十六进制值的形式将其写回 .rc2 文件。

  • 来自标准 Windows 控件派生类的控件中使用的标准 Windows WS_ 或控件样式符号 — 例如,ES_AUTOHSCROLL 是为 IDD_SPIN_EDIT 对话框中的数值调节钮控件定义的。尽管 Visual C++ 在读取 .rc2 文件时可以解释这些符号,但 Visual C++ 将以十六进制值的形式将其写回 .rc2 文件。

  • “.rc 文件中的算法” - 标识 IDD_SPIN_EDIT 对话框中的控件的表达式(如“IDC_EDIT1+2”)将以单个十六进制值的形式由 Visual C++ 写回 .rc2 文件。

CTRLTEST 示例阐释了对于包含自定义控件(其样式由头文件中的常数定义)的对话框而言,使用 .rc2 文件的优缺点。对话框 IDD_WNDCLASS_EDITIDD_SPIN_EDIT 都包含样式以符号形式定义的自定义控件;但 IDD_WNDCLASS 在可由 Visual C++ 对话框编辑器编辑的 .rc 文件中指定,而 IDD_SPIN_EDIT 在只能手动编辑的 .rc2 文件中指定。

.rc 文件和 .rc2 文件用法的差别可归纳为以下几点。

对于 IDD_WNDCLASS_EDIT 对话框,资源脚本在 Ctrltest.rc 中定义。对于 IDD_SPIN_EDIT 对话框,资源脚本在 RES\Ctrltest.rc2 中定义。对于 IDD_WNDCLASS_EDIT 对话框,WNDCLASS 自定义控件是“paredit”,样式常数在 PAREDIT.H 中定义,示例样式常数是 PES_NUMBER。IDD_WNDCLASS_EDIT 可由 Visual C++ 编辑,但不能使用 #define 样式。IDD_SPIN_EDIT 不能由 Visual C++ 编辑,但可以使用 #define 样式。

使用时需权衡它们的利弊,如果使用 .rc2 文件,可以对自定义控件使用头文件中定义的可读符号样式,但无法使用 Visual C++ 对话框编辑器编辑 .rc2 文件。使用 Visual C++ 布置对话框比手动编写资源脚本容易;而且编写资源脚本更容易出错。另一方面,当 Visual C++ 对话框编辑器在自定义控件属性页中以十六进制形式显示样式时,样式不自记录。

关键字

此示例说明以下关键字:

AfxGetInstanceHandle;AfxMessageBox;AfxThrowResourceException;CBitmapButton::AutoLoad;CDC::FillRect;CDC::FrameRect;CDialog::DoModal;CDialog::EndDialog;CDialog::OnInitDialog;CDialog::OnOK;CDialog::OnSetFont;CEdit::Create;CEdit::SetSel;CFrameWnd::Create;CListBox::AddString;CListBox::CompareItem;CListBox::DrawItem;CListBox::GetItemData;CListBox::MeasureItem;CMenu::AppendMenu;CMenu::CreateMenu;CMenu::Detach;CMenu::DrawItem;CMenu::EnableMenuItem;CMenu::FromHandle;CMenu::GetMenuString;CMenu::MeasureItem;CRect::Width;CStatic::Create;CString::Format;CString::LoadString;CWinApp::InitInstance;CWnd::Attach;CWnd::EnableWindow;CWnd::FromHandle;CWnd::GetDlgCtrlID;CWnd::GetDlgItem;CWnd::GetDlgItemInt;CWnd::GetMenu;CWnd::GetParent;CWnd::GetWindowRect;CWnd::GetWindowText;CWnd::IsWindowEnabled;CWnd::MessageBox;CWnd::OnChar;CWnd::OnCommand;CWnd::OnVScroll;CWnd::PostNcDestroy;CWnd::SendMessage;CWnd::SetDlgItemInt;CWnd::SetFocus;CWnd::SetFont;CWnd::SetWindowPos;CWnd::ShowWindow;CWnd::SubclassDlgItem;CallWindowProc;GetBValue;GetClassInfo;GetGValue;GetRValue;GetSystemMetrics;HIWORD;IsCharAlpha;IsCharAlphaNumeric;LOWORD;MAKEINTRESOURCE;MAKELONG;MessageBeep;ModifyMenu;RGB;RegisterClass;SetWindowLong

说明:

某些示例(如此示例)尚未经过修改以反映 Visual C++ 向导、库和编译器中所做的更改,但仍演示了如何完成所需的任务。

请参见

其他资源

MFC 示例