📄 06.5.4 框架类窗口及本章小结.txt
字号:
// /////////////////////////// //////////////////////////// //////////////
#if !defined(AFX_MENU2VIEW_H一 _5A2699DB_5392_4BEA_AA9A_E384FB803B5E INC
LUDED一)
#define AFX MENU2VIEW-H--5A2699DB-5392-4BEA-AA9A-E384FB803B5E--INCLUDED-
#工f MSC VER > 1000
#pragma once
#endif // _MSC_VER > 1000
#include "Menu2Doc.h"
class CMenu2View : publ工c CView
{
protected: / / create from serialization only
CMenu2View() ; . DECLARE_DYNCREATE(CMenu2View)
再次编译Menu2程序,这时程序将顺利通过,问题解决了。
让我们再回到CMainFrame类的OnCommand函数,现在做一个测试,在这个函数内部添加一条显示消息框的代码,看看这个函数是不是确实捕获到了动态添加的菜单项的命令消息。添加后的OnCommand函数代码如例6-48所;f>(注意MessageBox函数添加的位置〉。
{?IJ 6-48
BOOL CMainFrame :: O口Co町Iffia口d(WPARAM wParam, LPARAM lParam)
{ // TODO : Add your specialized code here and / or call the base class int MenuCmdID = LOWORD(wParam); CMenu2飞Tiew *pView = (CMenu2View *)GetActiveView() ; if ( MenuCmd工D>=工DM_PHONEl && MenuCmdID <工DM_PHONEl + pView->m_ strArray .
GetSize() ) { MessageBox ( "Test " ) ;
return CFrameWnd : :OnCommand(wParam, lParam);
Build并运行Menu2程序,读者可以随意输入一行文字,例如: aaa 12345,然后按下回车键,即可看到程序的菜单条上多了一个子菜单: PhoneBook,打开此菜单,可以看到它有一个菜单项: aaa,单击这个菜单项,程序随即弹出一个对话框,上面显示的文字是: "Test",说明确实是 CMainFrame类的OnCommand函数响应了这个菜单项命令。这就证明了 CMainFrame类确实捕获到了动态添加的菜单的命令。关闭这个信息框,随即看到程序窗口上显示了这个菜单项对应的文字,我们知道这是刚才在视类中为这个菜单命令添加的响应函数起作用的结果。这说明:框架类 (CMainFrame类)首先捕获到这个菜单命令,
"‘ I 217
第 6章禀单
然后视类也捕获到了这个命令。我们查看一下例 6-48所示 CMainFrame类 OnCommand函数的实现代码,当程序框架把消息传递给其子类 CMainFrame类的 OnCommand函数时,该函数就捕获到了一条消息,然后判断该消息是否是动态添加的菜单项命令消息,如果不是,则直接交由基类: CFrameWnd类的 OnCommand函数继续消息路由:如果是,就对其进行处理 (本例中就是显示一个对话框 ),然后把该消息仍交给基类: CFrameWnd类的 OnCommand函数继续消息路由。后者会将消息传递给程序的视类: CMenu2View,如果该类对当前消息有响应,就由视类的这个响应函数处理,消息路由结束。本例中,我们先前
已经对动态添加的菜单项为 CMenu2View类添加了命令响应函数,所以这里,当框架类响应了这个消息后,视类仍会做出响应。
为了只让框架类捕获到这些动态菜单命令消息,那么应该在框架类对这些消息做出响应之后,不要让它们再继续路由了。也就是框架类对这些消息处理完成之后返回一个 TRUE值,这样,这些消息就不会再交给基类 CFrameWnd类的 OnCommand函数,它们也就不会再继续路由了。我们可以试验一下,在上述例 6-48所示 CMainFrame类 OnCommand函数中刚才添加的 MessageBox函数之后,再添加下面这条语句:
return TRUEi
运行 Menu2程序,输入一行文字,例如: aaa 12345,然后按下回车键,打开新添加的【 PhoneBook】子菜单,并单击它下面的【 aaa】菜单项,这时程序会显示一个对话框,根据它上面显示的信息: Test,我们可以知道这是 CMainFrame类的 OnCommand函数作出的响应,关闭这个对话框。程序并没有像先前那样在窗口中显示对应的文字信息了。说明这个【 aaa】菜单项的命令消息仅由 CMainFrame类捕获到,并没有继续路由了。
下面,我们完善框架类的 OnCommand函数,当它捕获到动态菜单项的命令后,在窗
口中显示相应的文字,即接管视类先前的工作。具体实现代码如例 6-49所示。
19IJ 6-49
、
BOOL CMai nFrame : : OnCommand(WPARAM wParam , LPARAM lparam)
// TODO: Add your specialized code here and/or call the base cl ass int MenuCmd工 D = LOWORD(wParam) i CMenu2View *pView = (CMenu2Vi ew *)GetActi veView( ) i if ( MenuCmdID >= IDM一 P H ON El && MenuCmdID <工 DM_PHONEl + pView->m_str Array .
GetSize () ) {
/ / MessageBox ( "Test " ) ; CClientDC dc(pView) i dc.TextOut(O , O, pView->m_ strArray.GetAt(MenuCmdID -工 DM_PHONE1) ) i return TRUEi
return CFrameWnd: :OnCommand(wParam, lParam) i
在上述例 6-49所示代码中,当截获了动态菜单项的命令消息时,就需要显示相应的文
…
详
字。根据前面的知识,我们知道要进行绘图操作,首先就需要创建一个设备描述表,因此这段代码首先创建了一个 CClientDC类对象: dc,但这时给这个类的构造函数传递的指针,并不是先前在视类中实现菜单命令响应函数时那样传递的是 this指针。这里的出is指针现在指向的是框架类: CMainFrame类。前面已经讲过:视类窗口一直位于框架类窗口之上,在程序窗口进行的绘图操作实际上是在视类窗口中进行的,所以这里应该创建的是与视类窗口相关联的设备描述表对象。于是,上述例 6-49所示代码中,利用先前已经获得的与框架类相关的当前视类指针作为参数来创建设备描述表对象。
然后,需要根据当前单击的菜单项命令,从 StringArray中得到应该显示的文字。因为每次显示的文字在 StringArray中的位置都不同,所以不能给 GetA t函数传递一个固定的数字作为参数。为了让程序响应菜单选择的这种动态变化,可以用当前传递进来的命令 B减去 IDM_PHONl,得到当前应显示的字符串在 StringArray中的位置。我们可以验证一下,看看这种方法对不对,假设传进来的是 IDM_PHONTl,那么减去 IDM PHONT1后得到数值 0,即从 StringArray中取出第 1个元素,这是对的:假设传进来的是 IDM_PHONT2 , 减去 IDM_PHONT1后得到数值 L即从 StringArray中取出第 2个元素,也是对的。读者可以继续这样分析下去,从而验证这种方法是正确的。这样,就可以动态地将数组中保存的人名和电话号码取出来了。
Build并运行 Menu2程序,任意输入几行文字并回车,例如:
aaa 12345/
bbb 54321/
然后,在新添加的【 PhoneBook】子菜单下分别选择【 aaa】和【 bbb】菜单项,可以发现程序窗口中正确地显示了相应的文字内容。刚才我们已经验证了视类不再响应这些菜单项命令,因此这里显示的结果都是由 CMainFrame类的 OnCornrnand函数做出的响应。从而就实现了本应由视类捕获的命令消息被框架类截获了。
本章主要是关于菜单编程方面的内容,可以分为两大块:静态菜单操作和动态菜单操作。其中,静态菜单操作包括标记菜单、默认菜单、图形菜单的实现原理及具体实现,快捷弹出菜单的实现方式及其命令响应函数的添加。动态菜单操作主要包括:如何让程序在运行时产生新的子菜单和菜单项,以及如何手工地为这些新产生的菜单项命令添加响应处理函数。本章最后以一个小例子对菜单编程进行了一个实战演练,并实现了如何在顶层窗口,即框架类窗口中截获对菜单命令的处理。相信学完本章的知识后,读者对菜单编程应该有了很好的掌握,应该了解了 Windows中消息的分类,以及菜单命令消息的路由过程,并更进一步熟悉了 CString类的应用。
'‘
圃'一
Windows应用程序工作的基本流程是从用户那里得到数据,经过相应的处理之后,再把处理结果输出到屏幕、打印机或者其他的输出设备上。那么,应用程序是如何从用户那里得到数据,并且再将修改后的数据显示给用户的呢?这就需要用到 Windows应用程序中一个很重要的用户接口一一对话框。
7.1
实际上,对话框就是一个窗口,它不仅可以接收消息,而且还可以被移动和关闭,甚
至可以在它的客户区中进行绘图。我们也可以将对话框看成是一个大容器,在它上面能够
放置各种各样的标准控件和扩展控件,使程序支持用户输入的手段更加丰富。
7.1.1 常用控件介绍
在 MFC中,所有的控件类都是由 CWnd类派生来的,因此,控件实际上也是窗口,实际上,控件通常是作为对话框的子窗口而创建的。另外,控件也可以出现在视类窗口、工具栏和状态条中。控件 CContro\)是独立的小部件,在对话框与用户的交互过程中,担任着主要角色。 VC++提供的控件的种类很多,如图 7.1显示了对话框中的一些基本控件。
图像刚牛编解框
静恋文本粗细但怯fJI复地&单4刷l
夕l胶鞋
组合缸
京'l'ift动条
在自戒WJ靠上下控件
边j盘条前牵动矗
#键树相盟握f叶
夕'1m凶牛
标签饺件
司画控件 富文本篇帽椎 aH蜡阳附ù)j娼扭P1I1'
μ历控仲F地hUWt
扩展It'-tll合他
自定义控件
图 7.1基本控件
220
'如如
MFC的控件类封装了控件的功能,表 7.1列出了一些常用的控件及其对应的控件类。表 7.1常用控件及对应的控件类
控件 功能 对应控件类
静态文本框 (Static Text) 显示文本,般不能接受输入信息 CStatic
图像控件(Picture) 显式位图、图标、方框和图兀文件,一般不能接受输入信息 CStatic
编镜框(田itBox) 输入并编辑正文,支持单行和多行编辑 CEdit
按钮( Button) 响应用户的输入,触发相应的事件 CButton
复选框 (Cb四:kBox) 用作选择标记,可以有选中、未选中和不确定种状态 CButton
单选按钮 (Radio Button) 用来从两个或多个选项中选中→项 CBut阳n
组框(Group Box) 显不正文和方框,主要用来将相关的一些控件(用于共同的目的)组织 在一起 CButton
列表框(List Box) 显示一个列表,用户可以从该列表中选择一项或多项 CListBox
组合框 (ComboBox) 是个编辑框和一个列表框的组合.分为简易式、下拉式和下拉列表式 CComboBox
滚动条 (Scroll Bar ) 主要用来从一个预定义范围值中迅速而有效地选取-个整数值 CScrolffiar
7.1.2 对话框的种类
有两种类型的对话框:模态 CModaD对话框和非模态 CModeless)对话框。
·模态对话框
e
模态对话框是指当其显示时,程序会暂停执行,直到关闭这个模态对话框后,才能继续执行程序中其他任务。例如,在 Word中利用【文件飞打开】菜单命令显示一个"打开"对话框后,再用鼠标去选择其他菜单,或者进行该对话框以外的任何操作时,只会听到嘟嘟声,这是因为"打开"对话框是一个模态对话框。模态对话框垄断了用户的输入,当一个模态对话框打开时,用户只能与该对话框进行交互,而其他用户界面对象接收不到输入信息。我们平时所遇到的大部分对话框都是模态对话框。
·非模态对话框
当非模态对话框显示时,允许转而执行程序中其他任务,而不用关闭这个对话框。典型的例子是 Windows提供的记事本程序中的"查找"对话框,该对话框不会垄断用户的输入,打开"查找"对话框后,仍可以与其他用户界面对象进行交互,用户可以一边查找,一边修改文章,这样,就大大方便了使用。
12 对话框的创
首先新建一个单文档类型的 MFC AppWiz缸d (exe)工程,工程名设定为: Mybole. 接着利用 Build命令生成程序,并执行这个新程序,然后打开该程序菜单栏上的【帮助】子菜单,并单击其中的【关于 Mybole..】菜单项,程序会弹出→个如图 7.2所示的对话框。这是 MFC为我们自动创建的一个"关于"对话框,主要用来显示程序的版本号和版权信息。
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -