目录
- 框架调用代码
- MFC 对象之间的关系
- 访问其他对象
- CWinApp:应用程序类
- initInstance 成员函数
- 运行成员函数
- OnIdle 成员函数
- ExitInstance 成员函数
- CWinApp 和 MFC 应用程序向导
- 特殊 CWinApp 服务
- Shell 注册
- 文件管理器拖放
- CWinAppEx 类
- 用于创建 OLE 应用程序的操作顺序
- 用于创建 ActiveX 控件的操作顺序
- 用于创建数据库应用程序的操作顺序
- 对话框数据交换
框架调用代码
当应用程序运行时,大多数控件流位于框架的代码中。 框架管理一个消息循环,当用户在视图中选择命令和编辑数据时,此消息循环将会从 Windows 中获取消息。 框架可以单独处理的事件根本不用依赖您的代码。 例如,框架知道如何关闭窗口以及如何退出应用程序以响应用户命令。 在处理这些任务时,框架会使用消息处理程序和 C++ 虚函数,以便为你提供响应这些事件的机会。 但是,你的代码没有控制权,控制权在框架手中。
框架将会针对应用程序特定的事件调用你的代码。 例如,当用户选择某个菜单命令时,框架会将该命令传递给一系列 C++ 对象:当前视图和框架窗口、与当前视图关联的文档、文档的文档模板和应用程序对象。 如果其中某个对象可以处理命令,则会调用相应的消息处理程序函数来进行处理。 对于任何给定的命令,调用的代码可能是你的,也可能是框架的。
MFC 对象之间的关系
为了帮助正确地对待文档/视图创建过程,请考虑正在运行的程序:文档、用于包含视图的框架窗口以及与文档关联的视图。
文档用于保留其视图的列表和指向创建它的文档模板的指针。
视图用于保留指向其文档的指针并且是其父框架窗口的子级。
文档框架窗口用于保留指向其当前活动视图的指针。
文档模板用于保留其打开的文档的列表。
应用程序用于保留其文档模板的列表。
窗口用于跟踪所有打开的窗口以便能将消息发送到这些窗口。
访问其他对象
任何对象均可通过调用全局函数 AfxGetApp 来获取指向应用程序对象的指针。
获取对应用程序中的其他对象的访问权限
文档 使用 GetFirstViewPosition 和 GetNextView 以访问文档的视图列表。
调用 GetDocTemplate 以获取文档模板。
视图 调用 GetDocument 以获取文档。
调用 GetParentFrame 以获取框架窗口。
文档框架窗口 调用 GetActiveView 以获取当前视图。
调用 GetActiveDocument 以获取附加到当前视图的文档。
MDI 框架窗口 调用 MDIGetActive 以获取当前处于活动状态的 CMDIChildWnd。
通常,框架窗口包含一个视图,但在某些情况下(例如在拆分窗口中),同一框架窗口包含多个视图。 框架窗口保留指向当前处于活动状态的视图的指针;该指针在其他视图激活时更新。
CWinApp:应用程序类
MFC 中的主应用程序类将封装 Windows 操作系统的应用程序的初始化、运行和终止。 基于框架生成的应用程序必须有且只有一个从 CWinApp 派生的类的对象。 创建窗口之前将构造此对象。
CWinApp 派生自 CWinThread,它表示应用程序的执行的主线程(可能有一个或多个线程)。 在最新版本的 MFC 中,InitInstance、Run、ExitInstance 和 OnIdle 成员函数实际上位于类 CWinThread 中。 此处将这些函数作为 CWinApp 成员进行了讨论,因为讨论的焦点是将对象的角色视为应用程序对象,而不是主线程。
应用程序类构成了应用程序的执行主线程。 使用 Win32 API 函数,还可以创建执行的辅助线程。 这些线程可使用 MFC 库。
与 Windows 操作系统的所有程序类似,框架应用程序具有 WinMain 函数。 但在框架应用程序中,您不编写 WinMain。 它由类库提供,并且在应用程序启动时调用。 WinMain 运行标准服务,如注册窗口类。 然后它调用应用程序对象的成员函数来初始化和运行该应用程序。 (您可通过重写 WinMain 调用的 CWinApp 成员函数来自定义 WinMain。)
若要初始化此应用程序,WinMain 将调用应用程序对象的 InitApplication 和 InitInstance 成员函数。 要运行应用程序的消息循环,WinMain 将调用 Run 成员函数。 终止时,WinMain 将调用应用程序对象的 ExitInstance 成员函数。
// learnvc1.cpp: 定义应用程序的类行为。
.......
.......
BOOL Clearnvc1App::InitInstance()
{
// 如果一个运行在 Windows XP 上的应用程序清单指定要
// 使用 ComCtl32.dll 版本 6 或更高版本来启用可视化方式,
//则需要 InitCommonControlsEx()。 否则,将无法创建窗口。
INITCOMMONCONTROLSEX InitCtrls;
InitCtrls.dwSize = sizeof(InitCtrls);
// 将它设置为包括所有要在应用程序中使用的
// 公共控件类。
InitCtrls.dwICC = ICC_WIN95_CLASSES;
InitCommonControlsEx(&InitCtrls);
CWinAppEx::InitInstance();
EnableTaskbarInteraction();
// 使用 RichEdit 控件需要 AfxInitRichEdit2()
// AfxInitRichEdit2();
// 标准初始化
// 如果未使用这些功能并希望减小
// 最终可执行文件的大小,则应移除下列
// 不需要的特定初始化例程
// 更改用于存储设置的注册表项
// TODO: 应适当修改该字符串,
// 例如修改为公司或组织名
SetRegistryKey(_T("应用程序向导生成的本地应用程序"));
LoadStdProfileSettings(4); // 加载标准 INI 文件选项(包括 MRU)
InitContextMenuManager();
InitKeyboardManager();
InitTooltipManager();
CMFCToolTipInfo ttParams;
ttParams.m_bVislManagerTheme = TRUE;
theApp.GetTooltipManager()->SetTooltipParams(AFX_TOOLTIP_TYPE_ALL,
RUNTIME_CLASS(CMFCToolTipCtrl), &ttParams);
// 注册应用程序的文档模板。 文档模板
// 将用作文档、框架窗口和视图之间的连接
CMultiDocTemplate* pDocTemplate;
pDocTemplate = new CMultiDocTemplate(IDR_learnvc1TYPE,
RUNTIME_CLASS(Clearnvc1Doc),
RUNTIME_CLASS(CChildFrame), // 自定义 MDI 子框架
RUNTIME_CLASS(Clearnvc1View));
if (!pDocTemplate)
return FALSE;
AddDocTemplate(pDocTemplate);
// 创建主 MDI 框架窗口
CMainFrame* pMainFrame = new CMainFrame;
if (!pMainFrame || !pMainFrame->LoadFrame(IDR_MAINFRAME))
{
delete pMainFrame;
return FALSE;
}
m_pMainWnd = pMainFrame;
// 分析标准 shell 命令、DDE、打开文件操作的命令行
CCommandLineInfo cmdInfo;
ParseCommandLine(cmdInfo);
// 调度在命令行中指定的命令。 如果
// 用 /RegServer、/Register、/Unregserver 或 /Unregister 启动应用程序,则返回 FALSE。
if (!ProcessShellCommand(cmdInfo))
return FALSE;
// 主窗口已初始化,因此显示它并对其进行更新
pMainFrame->ShowWindow(m_nCmdShow);
pMainFrame->UpdateWindow();
return TRUE;
}
int Clearnvc1App::ExitInstance()
{
//TODO: 处理可能已添加的附加资源
return CWinAppEx::ExitInstance();
}
// learnvc1.h: learnvc1 应用程序的主头文件
//
#pragma once
#ifndef __AFXWIN_H__
#error "在包含此文件之前包含 'pch.h' 以生成 PCH"
#endif
#include "resource.h" // 主符号
// Clearnvc1App:
// 有关此类的实现,请参阅 learnvc1.cpp
//
class Clearnvc1App : public CWinAppEx
{
public:
Clearnvc1App() noexcept;
// 重写
public:
virtual BOOL InitInstance();
virtual int ExitInstance();
// 实现
UINT m_nAppLook;
BOOL m_bHiColorIcons;
virtual void PreLoadState();
virtual void LoadCustomState();
virtual void SaveCustomState();
afx_msg void OnAppAbout();
DECLARE_MESSAGE_MAP()
};
extern Clearnvc1App theApp;
initInstance 成员函数
Windows 操作系统允许您运行同一应用程序的多个副本(也称为“实例”)。 每当应用程序的新实例启动时,WinMain 都将调用 InitInstance。
MFC 应用程序向导创建的标准 InitInstance 实现将执行以下任务:
作为其中心操作,将创建文档模板,该模板又会创建文档、视图和框架窗口。
从 .ini 文件或 Windows 注册表加载标准文件选项,包括最近使用的文件的名称。
注册一个或多个文档模板。
对于 MDI 应用程序,创建主框架窗口。
处理命令行以打开命令行上指定的文档或打开新的空文档。
你可以添加自己的初始化代码或修改向导编写的代码。
MFC 应用程序必须初始化为单线程单元 (STA)。 如果在 InitInstance 替代中调用 CoInitializeEx,请指定 COINIT_APARTMENTTHREADED(而不是 COINIT_MULTITHREADED)。
运行成员函数
框架应用程序会在 CWinApp 类的 Run 成员函数中花费其大部分时间。 初始化之后,WinMain 调用 Run 来处理消息循环。
Run 循环通过一个消息循环,检查消息队列中的可用消息。 如果有可用的消息,Run 调度它进行相应的操作。 如果没有可用的消息(通常是这种情况),则 Run 调用 OnIdle 来执行你或框架可能需要进行的任何空闲时间处理。 如果没有要执行的消息和空闲处理,则应用程序将进行等待,直到发生某些情况。 应用程序终止时,Run 调用 ExitInstance。 OnIdle 成员函数中的数字显示消息循环中的操作序列
OnIdle 成员函数
当没有 Windows 消息在处理时,框架将调用 CWinApp 成员函数 OnIdle。
重写 OnIdle 以执行后台任务。 默认版本更新用户界面对象的状态(如工具栏按钮)并执行框架在其操作过程中创建的临时对象的清除。 下图演示消息循环如何在队列中没有消息时调用 OnIdle。
ExitInstance 成员函数
每当应用程序的副本终止(通常是因为用户退出应用程序)时,就会调用类 CWinApp 的 ExitInstance 成员函数。
如果需要特殊清理处理(如释放图形设备接口 (GDI) 资源或释放在程序执行期间使用的内存),则重写 ExitInstance。 但是,标准项(如文档和视图)的清理由框架使用用于执行特定于这些对象的特殊清理的其他可重写函数提供。
CWinApp 和 MFC 应用程序向导
创建框架应用程序时,MFC 应用程序向导声明派生自 CWinApp 的一个应用程序类。 MFC 应用程序向导还会生成包含以下项的实现文件:
应用程序类的消息映射。
空类构造函数。
声明类的唯一对象的变量。
InitInstance 成员函数的标准实现。
应用程序类放置在项目标头和主源文件中。 创建的类和文件名称基于你在 MFC 应用程序向导中提供的项目名称。 查看这些类的代码的最简单方法是通过类视图。
类视图(Visual Basic、C#、C++)
“类视图”显示为“解决方案资源管理器”的一部分并作为单独窗口 。 “类视图”显示应用程序的元素。
上部窗格显示命名空间、类型、接口、枚举和类,下部窗格显示属于在上部窗格中所选类型的成员。
通过使用此窗口,可以移到源代码(或“对象浏览器”,如果该元素在解决方案外部进行定义)中的成员定义。不需要编译项目即可在“类视图”中查看其元素。 修改项目中的代码时,窗口进行刷新。
通过选择项目节点,然后选择“添加”按钮打开“添加新项”对话框,可以向项目添加代码 。 在单独的文件中添加代码。
如果项目签入源代码管理,则每个“类视图”元素均显示一个指示该文件源代码状态的图标。
该元素的快捷菜单上也提供常用的源代码管理命令,如“签出”、“签入”和“获取最新版本” 。
特殊 CWinApp 服务
除了运行消息循环以及支持你初始化应用程序然后进行清理之外,CWinApp 还提供了一些其他服务。
Shell 注册
默认情况下,MFC 应用程序向导使用户能够打开您的应用程序已创建的数据文件,方法是在文件资源管理器或文件管理器中打开它们。 如果你的应用程序是 MDI 应用程序,并且你为该应用程序创建的文件指定了扩展名,MFC 应用程序向导会将对 CWinApp 的 RegisterShellFileTypes 和 EnableShellOpen 成员函数的调用添加到它为你编写的 InitInstance 替代。
RegisterShellFileTypes 将您的应用程序的文档类型注册到文件资源管理器或文件管理器。 该函数可将项添加到 Windows 保留的注册数据库。 这些项注册每个文档类型、将文件扩展名与文件类型关联、指定用来打开应用程序的命令行并指定用来打开该类型的文档的动态数据交换 (DDE) 命令。
EnableShellOpen 通过以下方式完成这个过程:允许您的应用程序从文件资源管理器或文件管理器接收用来打开用户选择的文件的 DDE 命令。
CWinApp 中的此自动支持使您无需将 .reg 文件附加到您的应用程序或完成特殊安装工作。
如果要初始化应用程序的 GDI+(通过在 InitInstance 函数中调用 GdiplusStartup),则必须禁止 GDI+ 后台线程。
可通过将 GdiplusStartupInput 结构的 SuppressBackgroundThread 成员设置为 TRUE 来执行此操作。 禁止 GDI+ 后台线程时,应在进入和退出应用程序的消息循环之前调用 NotificationHook 和 NotificationUnhook。 有关这些调用的详细信息,请参阅 GdiplusStartupOutput。 因此,适合调用 GdiplusStartup 和挂钩通知函数的位置是在虚函数 CWinApp::Run 的替代中,如下所示:
int CMyWinApp::Run()
{
GdiplusStartupInput gdiSI;
GdiplusStartupOutput gdiSO;
ULONG_PTR gdiToken;
ULONG_PTR gdiHookToken;
gdiSI.SuppressBackgroundThread = TRUE;
GdiplusStartup(&gdiToken, &gdiSI, &gdiSO);
gdiSO.NotificationHook(&gdiHookToken);
int nRet = CWinApp::Run();
gdiSO.NotificationUnhook(gdiHookToken);
GdiplusShutdown(gdiToken);
return nRet;
}
如果不禁止后台 GDI+ 线程,DDE 命令可能在其主窗口创建前提前发给应用程序。 shell 发出的 DDE 命令可能提前中止,从而产生错误消息。
文件管理器拖放
可从文件管理器或文件资源管理器中的文件视图将文件拖动到您的应用程序的窗口中。 例如,您可能使一个或多个文件拖动到 MDI 应用程序的主窗口,应用程序可在其中为这些文件检索文件名和打开 MDI 子窗口。
为了在应用程序中启用文件拖放,MFC 应用程序向导会在 InitInstance 中为主框架窗口编写对 CWnd 成员函数 DragAcceptFiles 的调用。 如果您不想实现拖放功能,则可以移除该调用。
您还可以使用 OLE 实现更常见的拖放功能 — 在文档之间或文档中拖动数据。 相关信息,请参阅 OLE 拖放一文。
跟踪最近使用的文档
当用户打开和关闭文件时,应用程序对象将跟踪四个最近使用的文件。 这些文件的名称将添加到“文件”菜单并在更改时更新。 框架会将这些文件名存储在与您的项目同名的注册表或 .ini 文件中,并在您的应用程序启动时从文件中读取它们。 MFC 应用程序向导创建的 InitInstance 替代包含对 CWinApp 成员函数 LoadStdProfileSettings 的调用,该调用从注册表或 .ini 文件加载信息(包括最近使用的文件名)。
这些项按如下方式进行存储:
在 Windows NT、Windows 2000 和更高版本中,值存储到注册表项。
在 Windows 3.x 中,值存储在 WIN.INI 文件中。
在 Windows 95 和更高版本中,值存储在缓存版的 WIN.INI 中。
CWinAppEx 类
CWinAppEx 处理应用程序状态,将此状态保存到注册表,从注册表加载此状态,初始化应用程序管理器,并将链接提供到同样的应用程序管理器。
公共方法
“属性” 说明
CWinAppEx::CleanState 从 Windows 注册表中移除应用程序的相关信息。
CWinAppEx::EnableLoadWindowPlacement 指定应用程序是否将从注册表加载主框架窗口的初始大小和位置。
CWinAppEx::EnableTearOffMenus 为应用程序启用可拖曳菜单。
CWinAppEx::EnableUserTools 允许用户在应用程序中创建自定义菜单命令。
CWinAppEx::ExitInstance 由框架从 Run 成员函数内调用以退出此应用程序实例。 (重写 CWinApp::ExitInstance。)
CWinAppEx::GetBinary 读取与指定的注册表值关联的二进制数据。
CWinAppEx::GetContextMenuManager 返回指向全局 CContextMenuManager 对象的指针。
CWinAppEx::GetDataVersion
CWinAppEx::GetDataVersionMajor 返回在 Windows 注册表中保存的应用程序的主版本。
CWinAppEx::GetDataVersionMinor 返回在 Windows 注册表中保存的应用程序的次要版本。
CWinAppEx::GetInt 从注册表中读取与指定值关联的数值数据。
CWinAppEx::GetKeyboardManager 返回指向全局 CKeyboardManager 对象的指针。
CWinAppEx::GetMouseManager 返回指向全局 CMouseManager 对象的指针。
CWinAppEx::GetObject 从注册表中读取与指定值关联的 CObject 派生数据。
CWinAppEx::GetRegSectionPath 返回注册表项路径的字符串。 该路径将提供的相对路径与应用程序路径连接起来。
CWinAppEx::GetRegistryBase 返回应用程序的注册表路径。
CWinAppEx::GetSectionBinary 从注册表中读取与指定键和值关联的二进制数据。
CWinAppEx::GetSectionInt 从注册表中读取与指定键和值关联的数值数据。
CWinAppEx::GetSectionObject 从注册表中读取与指定键和值关联的 CObject 数据。
CWinAppEx::GetSectionString 从注册表中读取与指定键和值关联的字符串数据。
CWinAppEx::GetShellManager 返回指向全局 CShellManager 对象的指针。
CWinAppEx::GetString 从注册表中读取与指定值关联的字符串数据。
CWinAppEx::GetTooltipManager 返回指向全局 CTooltipManager 对象的指针。
CWinAppEx::GetUserToolsManager 返回指向全局 CUserToolsManager 对象的指针。
CWinAppEx::InitContextMenuManager 初始化 CContextMenuManager 对象。
CWinAppEx::InitKeyboardManager 初始化 CKeyboardManager 对象。
CWinAppEx::InitMouseManager 初始化 CMouseManager 对象。
CWinAppEx::InitShellManager 初始化 CShellManager 类
CWinAppEx::InitTooltipManager 初始化 CTooltipManager 类。
CWinAppEx::IsResourceSmartUpdate
CWinAppEx::IsStateExists 指示注册表中是否存在指定的键。
CWinAppEx::LoadState 从注册表加载应用程序状态。
CWinAppEx::OnAppContextHelp 当用户请求“自定义”对话框的上下文帮助时由框架调用。
CWinAppEx::OnViewDoubleClick 当用户双击应用程序中的任意位置时调用用户定义的命令。
CWinAppEx::OnWorkspaceIdle
CWinAppEx::SaveState 将应用程序框架状态写入 Windows 注册表。
CWinAppEx::SetRegistryBase 设置默认注册表项的路径。 此项将用作所有后续注册表调用的根。
CWinAppEx::ShowPopupMenu 显示弹出菜单。
CWinAppEx::WriteBinary 将二进制数据写入指定的注册表值。
CWinAppEx::WriteInt 将数值数据写入指定的注册表值。
CWinAppEx::WriteObject 将从 CObject 类派生的数据写入指定的注册表值。
CWinAppEx::WriteSectionBinary 将二进制数据写入指定的注册表项的值。
CWinAppEx::WriteSectionInt 将数值数据写入指定的注册表项的值。
CWinAppEx::WriteSectionObject 将从 CObject 类派生的数据写入指定的注册表项的值。
CWinAppEx::WriteSectionString 将字符串数据写入指定的注册表项的值。
CWinAppEx::WriteString 将字符串数据写入指定的注册表值。
用于创建 OLE 应用程序的操作顺序
下表显示了创建 OLE 链接和嵌入应用程序的角色和框架角色。 这些表示可用选项,而不是要执行的步骤序列。
创建 COM 组件。 运行 MFC 应用程序向导。 在“复合文档支持”选项卡中选择“全服务器”或“微型服务器”。 框架生成启用了 COM 组件功能的框架应用程序。 所有 COM 功能都可以传输到现有应用程序,只需稍作修改。
从头开始创建容器应用程序。 运行 MFC 应用程序向导。 在“复合文档支持”选项卡中选择“容器”。使用类视图,转到源代码编辑器。 为 COM 处理程序函数填写代码。 框架生成一个框架应用程序,该应用程序可以插入 COM 组件(服务器)应用程序创建的 COM 对象。
从头开始创建支持自动化的应用程序。 运行 MFC 应用程序向导。 从“高级功能”选项卡中选择“自动化”。使用类视图在应用程序中公开用于自动化的方法和属性。 框架生成可由其他应用程序激活和自动化的框架应用程序。
用于创建 ActiveX 控件的操作顺序
下表显示了在创建 ActiveX 控件(以前称为 OLE 控件)时的角色和框架的角色。
1.创建 ActiveX 控件框架。 运行 MFC ActiveX 控件向导以创建控件。 在选项页中指定您需要的选项。 选项包括项目中控件的类型和名称、许可、子类和 About Box 方法。 MFC ActiveX 控件向导为具有基本功能的 ActiveX 控件创建文件,包括应用程序、控件和属性页的源文件、资源文件、项目文件和其他,均根据你的规格定制。
2.无需添加自己的代码,即可查看控件和 Activ eX 控件向导提供的功能。 生成 ActiveX 控件,并使用 Internet Explorer 或 TSTCON 示例对其进行测试。 正在运行的控件能够调整大小并移动。 它还有一个可以调用的 About Box 方法(如果选择)。
3.实现控件的方法和属性。 添加成员函数以提供控件数据公开接口,以实现特定于控件的方法和属性。 添加成员变量以保存数据结构,并在确定时使用事件处理程序触发事件。 框架已经定义了一个映射以支持控件的事件、属性和方法,让你专注于属性和方法的实现方式。 默认属性页可查看,并且提供了默认 About Box 方法。
4.构造控件的属性页。 使用 Visual C++ 资源编辑器直观地编辑控件的属性页界面:
- 创建其他属性页。
- 创建并编辑位图、图标和光标。
你还可以在对话框编辑器中测试对话框。 MFC 应用程序向导创建的默认资源文件提供了很多您需要的资源。 利用 Visual C++,您可以轻松直观地编辑现有资源和添加新资源。
5.测试控件的事件、方法和属性。 重新生成控件并使用测试容器来测试处理程序是否正确工作。 可以调用控件的方法,并通过属性页接口或通过测试容器控制其属性。 此外,使用测试容器跟踪从控件触发的事件和控件容器收到的通知。
用于创建数据库应用程序的操作顺序
下表显示在编写数据库应用程序时的角色和框架角色。
Visual C++ 环境和向导不支持 DAO(尽管包含 DAO 类且你仍可以使用它们)。 Microsoft 建议将 ODBC 用于新的 MFC 项目。 应只在维护现有应用程序时使用 DAO。
决定是否使用 MFC ODBC 或 DAO 类。 将 ODBC 用于新的 MFC 项目。 仅使用 DAO 来维护现有应用程序。 有关常规信息,请参阅数据访问编程一文。 框架提供了支持数据库访问的类。
使用数据库选项创建主干应用程序。 运行 MFC 应用程序向导。 选择“数据库支持”页上的选项。 如果选择创建记录视图的选项,则还应指定:
- 数据源和表名或名称
- 查询名称或名称。 MFC 应用程序向导创建文件并指定必要包含内容。 根据指定的选项,文件可以包含记录集类。
设计数据库窗体或窗体。 使用 Visual C++ 对话编辑器在记录视图类的对话框模板资源上放置控件。 MFC 应用程序向导会创建一个空对话模板资源,供你填写。
根据需要创建其他记录视图和记录集类。 使用类视图创建类以及使用对话编辑器来设计视图。 类视图为新类创建其他文件。
根据需要在代码中创建记录集对象。 使用每个记录集来操作记录... 记录集基于使用向导从 CRecordset 派生的类。 ODBC 使用记录字段交换 (RFX) 在数据库与记录集的字段数据成员之间交换数据。 如果使用记录视图,对话数据交换 (DDX) 在记录集与记录视图上的控件之间交换数据。
...或在代码中为要打开的每个数据库创建一个显式 CDatabase。 记录集对象以数据库对象为基础。 数据库对象提供到数据源的接口。
将数据列动态绑定到记录集。 在 ODBC 中,添加代码到派生记录集类以管理绑定。 请参阅记录集:动态绑定数据列 (ODBC) 一文。
对话框数据交换
对话框数据交换 (DDX) 是一种在对话框中初始化控件以及按用户收集数据输入的简单方式。 对话框数据验证 (DDV) 是一种在对话框中验证数据输入的简单方式。 若要在对话框中利用 DDX 和 DDV,请使用添加成员变量向导来创建数据成员并设置其数据类型和指定验证规则。
如果使用 DDX 机制,则可设置对话框对象的成员变量的初始值(通常在 OnInitDialog 处理程序或对话框构造函数中)。 就在显示对话框之前,框架的 DDX 机制会将成员变量的值传输到对话框中的控件,当对话框本身为响应 DoModal 或 Create 而出现时,这些控件将会显示在对话框中。 OnInitDialog 中的 CDialog 的默认实现调用 UpdateData 类的 CWnd 成员函数以在对话框中初始化控件。
当用户单击“确定”按钮时(或在你每次使用 TRUE 自变量调用 UpdateData 成员函数时),同一个机制都会将值从控件传输到成员变量。 对话框数据验证机制将验证为其指定了验证规则的所有数据项。
UpdateData 可以在两个方向进行,具体由传递给它的 BOOL 参数指定。 若要执行交换,UpdateData 将设置 CDataExchange 对象并调用对话框类的 CDialog 的 DoDataExchange 成员函数的重写。 DoDataExchange 采用 CDataExchange 类型的参数。 传递给 CDataExchange 的 UpdateData 对象表示交换的上下文,并将此类信息定义交换的方向。
当你(或代码向导)重写 DoDataExchange 时,可以指定对每个数据成员(控件)调用一个 DDX 函数。 每个 DDX 函数都了解如何基于由 CDataExchange 传递给 DoDataExchange 的 UpdateData 自变量提供的上下文双向交换数据。
MFC 提供了许多用于不同类型交换的 DDX 函数。 以下示例演示了一个 DoDataExchange 重写,其中调用两个 DDX 函数和一个 DDV 函数:
void CTestDialog::DoDataExchange(CDataExchange* pDX)
{
CDialog::DoDataExchange(pDX);
DDX_Check(pDX, IDC_MY_CHECKBOX, m_bVal);
DDX_Text(pDX, IDC_MY_TEXTBOX, m_strName);
DDV_MaxChars(pDX, m_strName, 20);
}
DDX_ 和 DDV_ 行是数据映射。 显示的示例 DDX 和 DDV 函数分别为复选框控件和编辑框控件。
如果用户取消模式对话框,OnCancel 成员函数将终止对话框,并且 DoModal 将返回 IDCANCEL 值。 在这种情况下,对话框和对话框对象之间不交换数据。
除了数据交换之外,还可以通过调用 DDV 函数指定验证,如对话框数据交换中的示例所示。 示例中的 DDV_MaxChars 调用验证在文本框控件中输入的字符串长度不超过 20 个字符。 如果验证失败,DDV 函数通常会使用消息框提醒用户,并且重点关注有问题的控件,以便用户可以重新输入数据。 给定控件的 DDV 函数必须在同一控件的 DDX 函数之后立即调用。