网上第一本以TXT格式的VC++深入详解孙鑫的书.全文全以TXT格式,并每一章节都分了目录,清晰易读

源代码在线查看: 07.3 动态创建按钮.txt

软件大小: 956 K
上传用户: kzdai22
关键词: TXT VC 目录
下载地址: 免注册下载 普通下载 VIP

相关代码

				7.3 动态创建按钮
				下面,我们要实现这样的功能:当单击对话框中某个按钮时,就在对话框中动态创建一个新按钮。
				因为非模态对话框实现较为麻烦,所以本章下面的内容仍以模态对话框为例。首先将 CMyboleView类的 OnDialog函数中创建非模态对话框的代码注释起来,并把先前创建模态对话框的代码的前面的注释符删除,即恢复上述例7-4所示的OnDialog函数实现。然后,为 IDD DIALOGl这个对话框添加一个按钮,方法是:用鼠标双击ResourceView选项卡上的 IDD一DIALOGl这个对话框资源 ID,将在资源编辑窗口中打开对应的对话框资源,接着用鼠标单击控件面板上的按钮 (Button)控件,然后在对话框中适当位置上拖放出一个合适大小的按钮,井在此按钮上单击鼠标右键,在弹出的快捷菜单中选择【Properties】t 菜单命令,即可显示这个按钮的属性对话框,利用这个对话框,我们将这个按钮的 ID属性设置为: IDC_BTN_ADD, Caption属性设置为: Add。如图7.12所示。
				下面,我们就实现当单击这个Add按钮后,在对话框中动态创建一个按钮这一功能。为了实现单击按钮就动态创建按钮这一功能,首先需要响应Add按钮单击消息,即为程序添加Add按钮单击消息的响应函数。添加方法是:用鼠标右键单击【Add】按钮,在弹出的快捷菜单中选择【ClassWizard..】菜单项,即可出现MFCClassWizard对话框,如图7.l3所示。因为现在是对CTestDlg对话框进行操作,所以类名 (Classname)应选择CTestDlg,并在Messages列表中选择BN_CLICKED消息。单击【Add Function...】按钮,并接受 ClassWizard自动设置的函数名: OnBtnAdd,然后单击【EditCode】按钮,即可定位到这个函数的定义处。
				Windows消息分为三类:标准消息、命令消息和通告消息。像按钮的单
				击、列表框的选择这类消息都属于通告消息。 
				为 Add按钮添加按钮单击消息响应函数章中已经介绍了,读者可以回顾一下。我们先为
				CTestDlg类添加一个私有的 CButton成员变量 : 
				果想要创建一个按钮,可以调用 CButton类的成员函数 Create来实现,例 7-9就是具体的
				
				关于动态创建按钮这一操作,第 3
				m btn。根据第 3章的知识,我们知道如
				
				实现代码。
				
				例 7-9 
				
				void CTestDlg : : OnBtnAdd(} 
				
				// TODO: Add your control notification handler code here 
				m_btn.Create("New" , BS_DEFPUSHBUTTON | WS_VISIBLE | WS_CHILD , CRect(0 , 0, 100 , 100} , this , 123} ; 
				如果在这里,不知道按钮的类型,可以求助于MSDN。
				
				上述代码在对话框窗口客户区的 ( 0,0 )处创建了一个文本为 "New"、长度和宽度均为 100个逻辑单位的按钮。注意:这里给这个新建按钮随意赋了一个 E号: 123。另外,还有一点需要提醒读者,如果在创建按钮时,没有指定 WS VISIBLE风格,那么随后一定要调用这个按钮对象的 ShowWindow函数,把该按钮控件显示出来。 
				Build井运行 Mybole程序,单击程序菜单栏上的【对话框】菜单,测试对话框出现了,单击该对话框上的【 Add】按钮,这时在该对话框的左上角就会出现一个动态创建的按钮: New,如图 7.14所示。
				但是,当我们再次单击【 Add】按钮时,程序就会弹出一个非法操作对话框,如图 7.15
				这是因为当单击 Add按钮后,就会调用 CButton的 Create函数,创建-个窗口,并与 m_btn这个对象相关联。当再次单击 Add按钮时,它又重复创建一个窗口并试图与 m_btn这个对象相关联,但因为此时 m_btn这个对象已经和一个窗口绑定在一起了,因此就会出现非法操作。
				为了解决这一问题,在程序中需要进行判断,如果 m_btn对象己经与一个窗口绑定在一起了,就需要先销毁这个窗口。当下次再单击 Add按钮时,再创建-个窗口并与 III-btn对象绑定。于是,我们为 CTestDlg类增加一个私有的 BOOL类型成员变量: m_bIsCreated, 用来标识是否是已经创建过按钮窗口了,井在 CTestDlg类的构造函数将此变量初始为 FALSE。然后在 Add按钮单击消息的响应函数 (OnBtnAdd)中,首先判断 m_bIsCreated这个变量的值,如果其值为 F丛SE,说明还没有创建按钮窗口,那就调用 Create函数创建,然后将 m_bIsCreated变量设置为 TRUE;否则销毁己创建的按钮窗口,这可以调用 CWnd类的成员函数: Des位oyWindow来实现(与这个函数对应的 SDK函数在第 1章中就已经用过了,相信大家不会对它感到陌生),然后将 m_bIsCreated变量设置为 TRUE。最终的实现代码如例 7-10所示。 
				例 7-10 
				
				void CTestDlg::OnBtnAdd() 
				{ 
				// TODO: Add your control notification handler code here 
				if(ffi_bIsCreated --FALSE) 
				
				m_btn.Create(nNew" , BS_DEFPUSHBUTTON | WS_VISIBLE | WS_CHILD, CRect(0 , 0, 100 ,100) , this, 123) ; 
				m_bisCreated = TRUE; 
				else 
				m_btn.DestroyWindow() ; 
				m_bIsCreated = FALSE; 
				
				Build井运行 Mybole程序,单击程序菜单栏上的【对话框】菜单,测试对话框出现了,单击该对话框上的【 Add】按钮,这时在该对话框的左上角就会出现一个动态创建的按钮 z New。再次单击【 Add】按钮,动态创建的 New按钮销毁了,当再次单击【 Add】按钮,又动态创建了 New按钮。程序一切正常。
				如果这里不用成员变量 m_bIsCreated,而是定义一个局部变量来进行判断,是否可行呢?例如,把上述例 7-10所示的代码修改为如例 7-11所示的代码。 
				例 7-11 
				
				void CTestDlg::OnBtnAdd() { // TODO: Add your control notification handler code here 
				44........ I 231 
				
				第 7 {甲3 
				
				
				BOOL bIsCreated = FALSE; 
				if(bIsCreated FALSE) 
				
				rrt-btrl.Create ( "New ", BS-DEFPUSHBUTTON|WS-V工 SIBLE I WS_CHILD , CRect(O , O, 100 , 100) , this , 123); bIsCreated = TRUE ; 
				else 
				ffi_btn.DestroyWindow() ; 
				bIsCreated = FALSE; 
				
				这时,在 OnBtnAdd函数中,首先定义了一个局部变量 bIsCreated,并初始化为 FALSE。然后对这个变量进行判断,根据其值来进行不同的处理。我们知道,由于 bIsCreated是局部变量,因此每次调用 OnB tnAdd函数时,这个局部变量都会被重新定义,并把它赋值为 FALSE,也就是说,每次执行的都是 if部分的语句。显然这是错误的。因此,这种方法行不通。
				如果要在每次调用 OnBtnAdd函数时,不再对 bIsCreated变量进行初始化,则可以将
				. 这个局部变量改成静态变量,即把 bIsCreated变量的定义代码改为: 
				static BOOL bIsCreated = FALSE; 
				对这个静态变量来说,当第一次加载 OnB tnAdd函数时,系统会为它分配内存空间,并初始化为 FALSE。以后再次进入 OnB tnAdd函数时,就不会再为这个静态变量分配内存空间井对它进行初始化操作了。读者可以试试这种方法,会发现同样能够实现正确的结果。
				以上我们是通过定义一个变量来判断是否已经创建了一个按钮窗口并与按钮对象相关联,下面利用一种更直接的方法来实现这种判断。根据前面的知识,我们知道 CWnd对象都有一个成员变量: m_hWnd,用来保存与窗口对象相关联的窗口句柄。如果窗口对象没有与任一个窗口相关联,这个句柄就为 NULL。因此,在我们这个例子的 OnBtnAdd函数中,可以判断一下,如果 m btn这个按钮对象的窗口句柄确实为空,就创建按钮:否则就销毁。在窗口对象销毁时,会把它的窗口句柄设置为 NULL。因此,利用 CWnd类的窗口句柄成员实现本例所需功能的具体代码如例 7-12所示。
				例 7-12 
				void CTestDlg : : OnBtnAdd() 
				11 TODO : Add your control not工 fication handler code here if(!ffi_btn .ffi_hWnd) { 
				ffi_btn.Create("New" , BS_DEFPUSHBUTTON I WS_VISIBLE I WS_CHILD , CRect(O , O, 100 , 100) , this , 123); 
				else 
				232 I势" V仇+深λ详解 
				m_bt口. DestroyWindow() ; 
				读者可以测试一下这时的Mybole程序,将会看到同样的效果。
				实际上,有多种方法可以实现Mybole程序中的这种判断,但上面我们使用的最后一种方法是最简单的,也是最直接的方法。当然,这就要求我们对MFC的 CWnd类有一定的了解,才会想到利用这种方法来实现。 
							

相关资源