基于对话框的应用程序-6868le自定义导航.ppt
第9章对话框和控件,9.1 对话框类CDialog 9.2 基于对话框的应用程序 9.3 模态对话框与非模态对话框 9.4 标准控件 9.5 公用对话框 习题,9.1 对话框类CDialog 在MFC中,对话框的功能都封装在CDialog类中,CDialog类是用来在屏幕上显示和管理对话框的基类。无论是基于对话框的应用程序,还是作为程序资源的模态对话框和非模态对话框,为了显示对话框和定义对话框的行为和功能,都需要从CDialog类派生一个对话框类。一个对话框对象是一个对话框模板资源和一个CDialog派生类的结合。要创建一个对话框,首先要创建一个对话框模板资源,可以使用对话框编辑器创建对话框模板资源并存储在资源文件中,然后利用ClassWizard创建一个基于对话框模板资源的从CDialog派生的对话框类。对话框模板资源指定了对话框本身的属性(如大小、位置、风格、类型等)和对话框中的控件及属性,对话框类规定了对话框和对话框中每个控件的行为。通过对话框模板资源才能创建对话框类和对象。,CDialog类是CWnd类的派生类,继承了CWnd类的成员。因此,对话框具有窗口的一切功能。CDialog类的派生关系如图9-1所示。,图9-1 CDialog类的派生关系,CDialog类提供了管理对话框的成员函数,同时,CWnd类也提供了管理对话框和控件的成员函数和管理一般窗口的函数,可以在对话框类的消息处理函数中调用这些成员函数。CDialog类中有关对话框处理的常用函数如下:(1)CDialog:通过派生类构造函数调用,根据对话框模板资源定义一个对话框对象。函数原型为:CDialog(LPCTSTR lpszTemplateName,CWnd*pParentWnd=NULL);CDialog(UINT nIDTemplate,CWnd*pParentWnd=NULL);CDialog();其中,参数“lpszTemplateName”为对话框模板资源名,“nIDTemplate”为对话框模板资源ID。,(2)Create:根据对话框模板资源创建非模态对话框窗口。如果对话框模板资源不具有Visible属性,则需要调用CWnd:ShowWindow()函数才能显示对话框。函数原型为:BOOL Create(LPCTSTR lpszTemplateName,CWnd*pParentWnd=NULL);BOOL Create(UINT nIDTemplate,CWnd*pParentWnd=NULL);其中,参数“lpszTemplateName”为对话框模板资源名,“nIDTemplate”为对话框模板资源ID。(3)DoModal:激活模态对话框,并显示对话框窗口。当对话框关闭时函数才返回对话框结果。函数原型为:virtual int DoModal();,(4)EndDialog:关闭模态对话框。函数原型为:void EndDialog(int nResult);其中,参数“nResult”为DoModal关闭对话框时的返回值。(5)OnInitDialog:WM_INITDIALOG消息的处理函数。在调用DoModal或Create函数时系统发送WM_INITDIALOG消息。当创建对话框后、显示之前调用该函数进行初始化工作。函数原型为:virtual BOOL OnInitDialog();,(6)OnOK:单击对话框的OK按钮(ID为IDOK)时调用。在派生对话框类中重载该函数可执行OK按钮命令。如果对话框包含自动的数据检验和交换,则该函数缺省实现对应用程序的某些变量进行数据检验和交换。在非模态对话框中实现OK按钮,必须重载OnOK函数,并在其中调用CWnd:DestroyWindow,但不能调用基类的OnOK函数,否则将会调用EndDialog,不能销毁对话框但使其不可见。函数原型为:virtual void OnOK();,(7)OnCancel:单击Cancel按钮或按ESC键时调用该函数。在派生对话框类中重载该函数可执行Cancel按钮命令。该函数缺省实现调用EndDialog终止模态对话框,并使DoModal返回IDCANCEL。在非模态对话框中实现Cancel按钮,必须重载OnCancel函数,并在其中调用CWnd:DestroyWindow,但不能调用基类的OnCancel函数,否则将会调用EndDialog,不能销毁对话框但使其不可见。函数原型为:virtual void OnCancel();另外,CDialog类还提供了对缺省按钮进行操作和在控件间移动输入焦点的函数。函数GetDefID返回对话框中缺省按钮的控件ID,通常为OK按钮。函数GotoDlgCtrl将输入焦点移到指定的控件上。函数NextDlgCtrl将输入焦点移动到下一个控件上。函数PrevDlgCtrl将输入焦点移动到前一个控件上。函数SetDefID将缺省按钮设置为指定ID的按钮。,CWnd类中有关窗口处理和对话框处理的常用函数如下:(1)DestroyWindow:关闭并销毁由CDialog:Create创建的对话框窗口。函数原型为:virtual BOOL DestroyWindow();(2)DoDataExchange:被UpdateData函数调用以实现对话框数据交换,不能直接调用。(3)GetWindowText:获取对话框标题或控件内的文本。函数原型为:int GetWindowText(LPTSTR lpszStringBuf,int nMaxCount)const;void GetWindowText(CString其中,参数“lpszStringBuf”为指向接收对话框标题字符串的指针,“nMaxCount”指定接收字符串的长度,“rString”为保存对话框标题的CString对象。,(4)GetDlgItemText:获取对话框控件的标题或文本。函数原型为:int GetDlgItemText(int nID,LPTSTR lpStr,int nMaxCount)const;int GetDlgItemText(int nID,CString其中,参数“nID”为指定控件的ID值,指向控件的指针由参数“phWnd”或函数返回。,(6)SetWindowText:用指定文本设置对话框的标题,对于控件则设置控件内文本。函数原型为:void SetWindowText(LPCTSTR lpszString);其中,参数“lpszString”为一个指向CString对象或以“0”结尾的字符串的指针,此字符串将作为对话框标题或控件内的文本。(7)SetDlgItemText:设置对话框控件的标题或文本内容。函数原型为:void SetDlgItemText(int nID,LPCTSTR lpszString);其中,参数“nID”为指定控件的ID值,“lpszString”为设置的字符串。,(8)MoveWindow:改变对话框的大小和位置。函数原型为:void MoveWindow(int x,int y,int nWidth,int nHeight,BOOL bRepaint=TRUE);void MoveWindow(LPCRECT lpRect,BOOL bRepaint=TRUE);其中,参数“x”和“y”指定对话框左上角坐标,“nWidth”和“nHeight”指定对话框的宽度和高度,“lpRect”指定对话框新的位置和大小。(9)EnableWindow:使对话框为禁用或可用状态。函数原型为:BOOL EnableWindow(BOOL bEnable=TRUE);若参数为“FALSE”,则对话框将被禁止使用;若参数为“TRUE”,则对话框允许使用。,(10)UpdateData:通过调用DoDataExchange函数设置或获取对话框控件的数据。函数原型为:BOOL UpdateData(BOOL bSaveAndValidate=TRUE);其中,参数“bSaveAndValidate”指明是用变量设置对话框控件(FALSE)还是获取对话框数据(TRUE)的标志。在CDialog:OnInitDialog函数的缺省实现中,以FALSE为参数调用UpdateData初始化对话框;在CDialog:OnOK函数的缺省实现中,以TRUE为参数调用UpdateData获取对话框数据。如果点击Cancel按钮,并不调用此函数,只关闭对话框,并不获取数据。(11)ShowWindow:显示或隐藏对话框窗口。函数原型为:BOOL ShowWindow(int nCmdShow);其中,参数“nCmdShow”指定窗口显示的方式。,(12)SetDlgItemInt:将整数转换为字符串并设置为控件的文本。函数原型为:void SetDlgItemInt(int nID,UINT nValue,BOOL bSigned=TRUE);其中,参数“nID”为要设置文本的控件的ID值,“nValue”为要转换为字符串的整数。(13)GetDlgItemInt:将指定控件的文本转换成整数并返回。转换时,跳过文本开始的空格,当到达文本的末尾或遇到非数字字符时停止转换。函数原型为:UINT GetDlgItemInt(int nID,BOOL*lpTrans=NULL,BOOL bSigned=TRUE)const;,9.2 基于对话框的应用程序 基于对话框的应用程序运行时就是一个对话框窗口。相对于其它结构的Windows程序要简单的多。可以利用AppWizard应用程序向导和ClassWizard类向导轻松地创建一个对话框应用程序。,创建一个基于对话框的应用程序可以分为以下几步:(1)利用AppWizard创建一个基于对话框的应用程序框架。(2)利用对话框编辑器以可视化的方法编辑对话框,放置各种控件并设置控件的属性。(3)使用C1assWizard在对话框类中添加数据成员、交换函数和有效性验证函数,为控件添加关联的成员变量。(4)使用ClassWizard为对话框的按钮和其它控件产生的事件添加消息处理函数。(5)对特殊控件进行初始化,为消息处理函数添加代码。,9.2.1 简单应用程序实例 下面通过一个简单的实例来说明创建对话框应用程序的方法和过程。【例9.1】编写一个如图9-2所示的对话框应用程序,完成简单的算术运算。,程序的创建过程如下:(1)利用AppWizard创建应用程序框架。执行“File”“New”菜单命令,打开“New”对话框(见图8-1)。选定“Projects”标签,选择项目类型“MFC AppWizardexe”,在“Project name”文本框中输入项目名EX9_1,在“Location”文本框中输入保存项目的路径和文件夹名,单击“OK”按钮。在随后出现的“MFC AppWizardStep1”对话框(见图8-2)中选择“Dialog based”,单击“Finish”按钮,就以缺省选项建立了应用程序框架,并在Visual C+的集成开发环境下打开对话框编辑器和控件工具栏,如图9-3所示。,图9-3 对话框编辑窗口,(2)添加控件并设置控件属性。一个对话框总是与控件相关联的,对话框的功能主要由各种控件来实现,因此,为了实现对话框的功能,必须利用对话框编辑器为对话框模板资源添加相应的控件。添加控件需要利用控件工具栏,如图9-4所示。控件工具栏上的每一个图标代表一种控件。若Visual C+窗口中没有出现控件工具栏,则只需在菜单栏或工具栏的空白处右击鼠标,在弹出的快捷菜单中选择“Controls”项即可。,图9-4 控件工具栏及控件说明,在对话框模板资源上添加控件的方法:在控件工具栏上单击要添加的控件图标,选择所需的控件,然后在对话框上按住鼠标左键在适当位置画出所需大小的控件。也可以在控件工具栏中选择所需控件后,在对话框指定位置处单击鼠标,则该控件被添加到对话框中指定的位置。本例中,先删除原有的控件,按图9-2所示,添加三个静态文本框、三个编辑框和四个命令按钮。若想改变控件的大小,对齐控件,删除或移动控件等,必须首先选择相应的控件。单击某个控件即可选中该控件。若要同时选择多个控件,一种方法是在对话框内按住鼠标左键不放,拖动鼠标画出一个虚线框,然后释放鼠标,则被该虚线框包围的控件都将被同时选中;另一种方法是按住Shift(或Ctrl)键不放,然后用鼠标分别单击需要选中的控件。,当有多个控件被同时选中时,其中有一个控件周围带有实心标志,其它为空心标志。当需要同时改变多个控件的大小或对齐多个控件时,对话框编辑器以带实心的控件来决定其它控件的大小和对齐方式。按住Ctrl键不放,单击某个控件,即可将实心标志移到该控件上。按住Shift键不放,单击被选中的控件,则可取消该控件的选中。为了调整对话框中控件的位置、大小和对齐控件等,可以使用如图9-5所示的对话框工具栏(一般位于Visual C+集成开发环境的底部)或使用“Layout”菜单来布局控件。只有当打开对话框编辑器时,才会出现Layout菜单。,图9-5 对话框工具栏,在调整控件布局时可以随时单击“测试对话框”按钮观察对话框的运行结果。控件的属性决定了控件的外观和功能。可以在添加控件的同时设置控件的属性,或者在控件添加结束后再设置属性。在对话框模板资源中右击需要设置属性的控件,在弹出的快捷菜单中选择“Properties”,或选中控件按回车键,则弹出如图9-6所示的控件的属性对话框。在对话框中可以选中某选项以设置该属性,或取消选中以清除该属性。若要设置多个控件的属性,可以按下属性窗口对话框左上角的图钉按钮,则属性对话框始终保持打开状态。,图9-6 控件的属性对话框,本例中,对第一个编辑框,在“General”标签下设置控件ID值为IDC_FIRSTNUM,其它属性采用缺省设置。表9-1列出了本例中所有控件的属性设置和添加的成员变量。,表9-1 例9.1中控件的属性设置和添加的成员变量,(3)利用ClassWizard可以在对话框类中添加数据成员、交换函数和有效性验证函数,为控件添加关联的成员变量。在对话框中添加控件后,可以利用ClassWizard在对话框类中为控件添加对应的成员变量,一个控件可以添加一个或多个成员变量。执行“View”“ClassWizard”菜单命令或按“Ctrl+W”快捷键或右击需要关联的成员变量的控件,在快捷菜单中选择“ClassWizard”,打开“MFC ClassWizard”对话框,选中“Member Variables”标签,如图9-7所示。在“Member Variables”标签下,可以在对话框类中为对话框中的控件添加关联的成员变量和删除变量。,图9-7 ClassWizard类向导的“Member Variables”标签,在“Member Variables”标签的Class name下拉列表框中选择要添加成员变量的对话框类,本例为CEX9_1Dlg。“Control IDs”列表框中列出了该对话框中所有控件的ID值。对话框中每一个控件都必须有一个ID值,每一个ID值唯一地代表一个控件。在“Control IDs”下选定需要关联的变量的控件ID,单击“Add Variable”按钮,将弹出如图9-8所示的“Add Member Variable”对话框。在“Member variable name”框中输入成员变量名,ClassWizard缺省以“m_”作为成员变量名的前缀。在“Category”下拉列表框中选择成员变量的类别,可以为Control或Value,在“Variable type”下拉列表框中选择成员变量的数据类型。,图9-8 添加成员变量对话框,若选择成员变量的类别为Value,则添加的成员变量用来保存控件的值或给控件赋值,这时可以在Variable type下拉列表框中为变量选择不同的数据类型。不同控件的成员变量可以选择的数据类型有所不同。若选择成员变量的类别为Control,则添加的成员变量就是代表控件本身的一个控件对象,其数据类型为控件所对应的MFC控件类。通过此控件对象可以访问控件类的成员函数,实现对控件的管理和控制。例如,对于编辑框,Control类别的成员变量的数据类型为类CEdit。可以为一个控件同时定义一个Value类别的变量和一个Control类别的变量,但有些控件只能定义Control类别的变量,如命令按钮控件。添加的成员变量的访问控制权限都为Public。,在“MFC ClassWizard”对话框的“Member Variables”标签下,如果选中的控件已经添加了成员变量,则单击“Delete Variable”按钮可以删除相应的成员变量。在添加Value类别成员变量的同时,还可以为此变量添加有效性验证数据,如变量的最大值和最小值、字符串的最大长度等。例如在图9-7中,可以在对话框的最下面两个文本框中输入变量的最大值和最小值。这时,ClassWizard将根据用户的指定生成相应的有效性验证函数,以确保在使用过程中数据的合法性。,本例中,为各控件添加的成员变量及数据类型见表9-1所示。(4)使用ClassWizard为对话框控件添加消息处理函数。在建立了用户界面、设置好控件属性和连接成员变量后,就要考虑为哪些控件编写什么样的消息处理函数了。本例中,当用户在编辑框中输入两个操作数后,单击“加”或“减”命令按钮对这两个操作数作相应的运算,因此,应为各命令按钮添加鼠标单击的消息处理函数,在函数中作相应的运算并输出结果。,执行“View”“ClassWizard”菜单命令或按“Ctrl+W”快捷键或右击需要关联成员变量的控件,在快捷菜单中选择“ClassWizard”,打开“MFC ClassWizard”对话框。在“Message Maps”标签下,选择Class name为“CEX9_1Dlg”,在“Object IDs”列表框中选定需要添加消息处理函数的控件ID,如IDC_ADD,在“Messages”列表框中选择BN_CLICKED消息,然后单击“Add Function”按钮,打开如图9-9所示的“Add Member Function”对话框,在其中输入消息处理函数的函数名(ClassWizard根据控件的ID符号给出了一个缺省函数名),单击“OK”按钮后,ClassWizard即为控件添加了一个消息处理函数。本例中为三个命令按钮添加的消息处理函数都采用ClassWizard给出的缺省函数名。,图9-9“Add Member Function”对话框,(5)为消息处理函数添加代码。利用项目工作区窗口的ClassView标签或“MFC ClassWizard”对话框定位到添加的消息处理函数,在其中添加相应的代码,完成程序的功能。本例中,单击按钮“加”的消息处理函数为:void CEX9_1Dlg:OnAdd()/TODO:Add your control notification handler code hereUpdateData();m_floatResult=m_floatFirstNum+m_floatSecondNum;UpdateData(FALSE);m_staticResult.SetWindowText(加法运算结果);/更新结果的提示文字,首先以TRUE为参数调用UpdateData(),将用户在编辑框中输入的数据保存到相应的成员变量中。进行加法运算后,以FALSE为参数调用UpdateData(),用成员变量的值更新控件,显示运算结果,并更新提示信息。单击按钮“减”的消息处理函数可以与消息处理函数OnAdd()相似。下面给出另一种不同的实现方法。,void CEX9_1Dlg:OnSubtract()/TODO:Add your control notification handler code hereCString strTemp;float firstnum,secondnum,result;m_editFirstNum.GetWindowText(strTemp);/获取编辑框内的输入firstnum=atof(strTemp);/将数字字符串转换为数值m_editSecondNum.GetWindowText(strTemp);secondnum=atof(strTemp);result=firstnum-secondnum;strTemp.Format(%g,result);/用运算结果格式化字符串m_editResult.SetWindowText(strTemp);/显示结果m_staticResult.SetWindowText(减法运算结果);,函数中利用各控件对应的Control类别的成员变量(即对象名),调用其成员函数获取编辑框中的输入文本,然后转换为数值进行计算。单击“退出”按钮的消息处理函数为:void CEX9_1Dlg:OnExit()/TODO:Add your control notification handler code hereOnOK();,9.2.2 理解应用程序框架 由AppWizard生成的基于对话框应用程序的框架主要有两类,一类是应用程序类,如CEX9_1App类,另一类是类CDialog的派生类,如CEX9_1Dlg类。应用程序类主要完成程序的初始化、启动和消息循环。同其它MFC应用程序相同,基于对话框的应用程序也有一个全局的应用程序对象,它代表应用程序自身。应用程序类中最关键的是AppWizard生成的CEX9_1App:InitInstance函数。一般的MFC应用程序的InitInstance函数生成一个框架窗口并返回TRUE,然后进入应用程序的消息循环(参见小节中函数AfxWinMain的代码)。而基于对话框应用程序中的InitInstance函数,通过调用函数DoModal创建模态对话框,然后返回FALSE,并不执行Run。,例9.1中InitInstance函数的主体如下所示:BOOL CEX9_1App:InitInstance()CEX9_1Dlg dlg;m_pMainWnd=,对话框有自己的消息循环,由DoModal函数启动对话框的消息循环。当用户退出对话框后,DoModal函数返回,应用程序就结束了。派生的对话框类用来定义对话框的行为、管理对话框控件和对控件的消息进行处理,其中包含四个关键函数:DoModal、OnInitDialog、OnOK和OnCancel。当应用程序对象调用函数InitInstance初始化对话框应用程序时,通过调用DoModal创建对话框,该函数只有在关闭对话框后才返回。,对话框创建后,对话框接收WM_CREATE消息,Windows用来处理对话框消息的内部窗口函数会响应WM_CREATE消息,创建对话框控件。创建控件后,对话框接收到一个WM_INITDIALOG消息。此时,对话框及其控件都已经创建完成但在屏幕上并不显示,因此,可以在响应此消息时对对话框进行必要的初始化,包括初始化控件。在CDialog的派生类中,对WM_INITDIALOG消息的响应函数为OnInitDialog。其函数原型为:virtual BOOL OnInitDialog();在派生类中重载的OnInitDialog函数,首先调用基类CDialog的OnInitDialog函数,此函数的缺省实现中以参数FALSE调用CWnd:UpdateData函数,通过UpdateData函数调用派生对话框类的DoDataExchange函数,将与控件相关联的成员变量的值传递给控件,即初始化控件。,提示:函数DoModal、OnInitDialog、OnOK和OnCancel的完整定义可以查看“XVC98MFCSRCDLGCORE.CPP”文件。函数CWnd:UpdateData的完整定义可以查看文件“XVC98MFCSRCWINCORE.CPP”。其中,“X”为安装VC6.0的路径,缺省为“C:Microsoft Visual Studio”。,当用户关闭并退出对话框时,函数DoModal返回。DoModal返回传递给EndDialog函数的参数。当通过OnOK关闭对话框时,DoModal返回IDOK;当通过OnCancel关闭对话框时,返回IDCANCEL。CDialog:OnOK函数以TRUE为参数调用CWnd:UpdateData函数,将控件的值保存到相关联的成员变量中,然后以IDOK为参数调用CDialog:EndDialog函数,关闭对话框。CDialog:OnCancel函数直接以IDCANCEL为参数调用CDialog:EndDialog函数,关闭对话框。对话框运行过程中的函数调用关系如图9-10所示(以例9.1进行说明)。,图9-10 对话框运行过程中的函数调用关系,9.2.3 对话框数据交换和验证 在例9.1的命令按钮“减”的消息处理函数OnSubtract中,通过调用CWnd:GetWindowText函数获取编辑框中的数据,通过调用CWnd:SetWindowText函数将成员变量的值写入编辑框中。虽然通过调用这些成员函数可以访问和更新对话框控件中的数据,但在对话框中实现数据输入和输出的更一般的方法是建立成员变量与相关控件的“数据映射表”,像OnAdd函数一样,利用对话框提供的对话框数据交换(DDX)和对话框数据验证(DDV)机制实现数据的输入和输出。,在上一小节已经知道,当调用DoModal创建对话框时,框架会自动调用DoDataExchange函数将成员变量的值传递给控件。当调用OnOK时,也要调用此函数将控件的值保存到成员变量中。函数DoDataExchange是CWnd类中的一个虚函数,在派生对话框类中重载此函数,可调用MFC提供的DDX函数实现对话框控件和成员变量间的数据传送。例9-1中派生类CEX9_1Dlg中重载的DoDataExchange函数如下:,void CEX9_1Dlg:DoDataExchange(CDataExchange*pDX)CDialog:DoDataExchange(pDX);/AFX_DATA_MAP(CEX9_1Dlg)DDX_Control(pDX,IDC_FIRSTNUM,m_editFirstNum);DDX_Control(pDX,IDC_SECONDNUM,m_editSecondNum);DDX_Control(pDX,IDC_STATICRESULT,m_staticResult);DDX_Control(pDX,IDC_RESULT,m_editResult);DDX_Text(pDX,IDC_FIRSTNUM,m_floatFirstNum);DDX_Text(pDX,IDC_RESULT,m_floatResult);DDV_MinMaxFloat(pDX,m_floatResult,-999999f,999999f);DDX_Text(pDX,IDC_SECONDNUM,m_floatSecondNum);/AFX_DATA_MAP,函数DoDataExchange中调用的每一个DDX函数将一个成员变量与一个控件联系起来,实现该成员变量与控件之间的数据交换。DDX函数是一个全局函数,其函数原型为:void AFXAPI DDX_type(CDataExchange*pDX,int nIDC,数据类型其中,“type”表示进行数据交换的控件类型,如DDX_Text对编辑框控件进行数据交换。参数“pDX”是一个指向CDataExchange对象的指针,应用程序框架通过此对象建立数据交换的环境及数据交换的方向。“nIDC”是进行数据交换的控件的资源ID值。“value”是进行数据交换的成员变量的引用,用来保存控件的值和传递数据。表9-2中列出了MFC中常用的部分DDX函数。,表9-2 对话框数据交换(DDX)函数,MFC提供的数据验证函数DDV用于在进行数据交换时检查数据的有效性,校验数值是否在指定的范围内或字符串是否超过规定的长度。DDV函数也被DoDataExchange函数调用。表9-3列出了MFC常用的DDV函数。,表9-3 对话框数据验证函数,可以通过手工编程方式将DDX和DDV函数添加到DoDataExchange函数中,也可以通过ClassWizard向导添加。当通过ClassWizard为控件添加成员变量时,ClassWizard自动在DoDataExchange中插入相应的DDX和DDV函数。需要注意的是,程序员不能在自己的程序中直接调用DoDataExchange函数,它一般由CWnd:UpdateData函数调用。除了在调用DoModal创建对话框和调用OnOK关闭对话框时会自动调用DoDataExchange进行数据交换和验证外,如果需要在程序运行中进行数据的交换,可以随时通过调用UpdateData函数来实现。当以TRUE为参数调用UpdateData函数(TRUE为UpdateData函数参数的缺省值)时,将数据从控件传送给关联的成员变量;当调用UpdateData(FALSE)时,将数据从成员变量传送给关联的控件。,9.3 模态对话框与非模态对话框 对话框除了可以作为一个应用程序外,在Windows中,对话框更多的是作为一个应用程序的资源。例如,执行“打开”菜单命令弹出一个打开文件的对话框。作为Windows应用程序资源的对话框分为模态对话框与非模态对话框。MFC将模态对话框与非模态对话框的功能都封装在CDialog类中。,9.3.1 模态对话框 在MFC Windows应用程序中增加一个模态对话框的步骤如下:(1)使用对话框编辑器创建包含各种不同控件的对话框模板资源。(2)使用ClassWizard创建基于对话框模板资源的对话框类,该类从CDialog类派生。(3)使用ClassWizard在对话框类中添加与控件关联的成员变量、对话框数据交换函数和验证函数。(4)使用ClassWizard为对话框中的控件产生的事件添加消息处理函数。(5)在OnInitDialog函数中添加代码,对特殊控件进行初始化,为消息处理函数添加功能代码。(6)在应用程序中定义对话框类的对象,调用DoModal打开对话框。,【例9.2】当用户单击单文档界面应用程序的视图窗口,可打开对话框,关闭对话框后在视图窗口中显示对话框的操作结果,如图9-11所示。,图9-11 例9.2程序运行时的窗口和对话框,程序的实现过程与编程说明如下:(1)利用AppWizard生成一个名为EX9_2的单文档界面应用程序。执行“File”“New”菜单命令,单击“Projects”标签,选择“MFC AppWizardexe”,输入项目名“EX9_2”,在下一步中选择“Single document”,其它接受缺省设置。(2)向应用程序中添加对话框资源,并用对话框编辑器添加控件,设置属性。向应用程序中添加一个对话框资源,可以使用以下两种方法:一是在项目工作区中选择“Resource View”标签,用鼠标右击资源类型项“Dialog”,从弹出的快捷菜单中执行“Insert Dialog”命令,插入一个对话框资源。二是,执行“Insert”“Resource”菜单命令,弹出“Insert Resource”对话框,如图9-12所示。在对话框中选中“Dialog”项,单击“New”按钮。在应用程序中插入一个对话框资源时,Visual C+同时打开对话框编辑器。,图9-12“Insert Resource”对话框,设置对话框的属性。右击对话框空白处,从快捷菜单中选择“Properties”,将ID值设置为IDD_STUDENTINFO,在Caption框中设置对话框标题为“学生信息登记”,其它接受缺省设置。按照图9-11所示向对话框中添加控件,并设置各控件的属性。程序中添加的控件及其属性设置如表9-4所示。,表9-4 在对话框中添加的控件及其属性设置,(3)使用ClassWizard创建基于对话框模板资源的对话框类。创建对话框模板资源后,需要在此模版资源的基础上创建一个对话框类。对话框模板资源指定了对话框本身的属性(如大小、位置、风格、类型等)和对话框中的控件及属性,决定对话框的外观。对话框类规定了对话框和对话框中每个控件的行为和功能。创建对话框类需要使用ClassWizard,过程如下:在对话框编辑器中打开新创建的IDD_STUDENTINFO对话框模板资源,执行“View”“ClassWizard”菜单命令或右击对话框空白处,在弹出的快捷菜单中选择“ClassWizard”命令,ClassWizard会检测到新添加的对话框模板资源没有关联的对话框类,将弹出如图9-13所示的“Adding a Class”对话框,询问是否需要利用该对话框资源创建一个对话框类。,图9-13“Add a Class”对话框,保持“Create a new class”为选中状态,单击“OK”按钮,弹出如图9-14所示的“New Class”对话框。,图9-14 创建对话框类的“New Class”对话框,在“Name”编辑框中输入对话框类名,例9.2中为CStudentInfoDialog,“File name”编辑框中列出了该类的文件名,可以单击“Change”按钮改变文件名。在“Base class”下拉列表框中选择对话框类的基类为CDialog,在“Dialog ID”下拉列表框中选择对话框模板资源ID为IDD_STUDENTINFO。单击“OK”按钮,ClassWizard即为对话框模板资源创建了关联的对话框类,并打开“MFC ClassWizard”对话框,再次单击“OK”按钮,退出ClassWizard。(4)使用ClassWizard在对话框类中添加与控件关联的成员变量。,程序中需要返回对话框中输入的姓名、学号和对专业与性别的选择,因此,在对话框类中需要添加与此四个控件关联的成员变量。对于一组单选按钮,只需要一个关联的成员变量。程序中添加的成员变量如表9-5所示。表9-5 与控件关联的成员变量,(5)使用ClassWizard为对话框中的控件产生的事件添加消息处理函数。在本例的对话框类CStudentInfoDialog中不需要添加控件的消息处理函数,因为CDialog类在Windows的帮助下完成了对话框管理的大部分工作。例如,当为“确定”按钮指定ID为IDOK(ClassWizard的缺省设置)时,用户单击“确定”按钮,则会自动调用CDialog类的虚函数OnOK;当为“取消”按钮指定ID为IDCANCEL(ClassWizard的缺省设置)时,用户单击“取消”按钮,则会自动调用CDialog类的虚函数OnCancel。但是,对于其它按钮或控件的消息则需要添加消息处理函数。方法见小节。,(6)使用ClassWizard添加OnInitDialog消息处理函数,在其中添加相应的代码对一些特殊控件进行初始化。当使用ClassWizard为编辑框、单选按钮等控件添加关联的成员变量时,ClassWizard自动地在类的构造函数中对这些成员变量进行初始化,同时在DoDataExchange函数中添加相应的DDX函数和DDV函数(如果用户指定了成员变量的验证值)。但对一些控件的特殊初始化,例如对列表框中选项的初始化,需要手工添加代码完成。这些初始化工作可以在OnInitDialog函数中完成。利用ClassWizard在对话框类CStudentInfoDialog中添加消息WM_INITDIALOG的消息处理函数OnInitDialog(方法见小节),在其中添加对列表框的初始化代码如下:,BOOL CStudentInfoDialog:OnInitDialog()CDialog:OnInitDialog();/TODO:Add extra initialization here/获得列表框控件的指针CListBox*pLB=(CListBox*)GetD