⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 06.5.3 添加菜单项及其命令晌应函数.txt

📁 网上第一本以TXT格式的VC++深入详解孙鑫的书.全文全以TXT格式,并每一章节都分了目录,清晰易读
💻 TXT
字号:
6.5.3 添加菜单项及其命令晌应函数
接下来,需要实现在输入人名、空格、电话号码,并当按下回车键后,把输入的人名作为菜单项的文本添加到PhoneBook子菜单下这一功能。
因为我们把当前输入的内容全部保存到m s位Line这个变量中,并且人名和电话号码之间是以空格分隔的,所以,首先需要从m strLine变量中分离出人名字符串。
CString类提供了一个 Find成员函数,这个函数在字符串中可以查找一个字符,或者一个字符串,返回匹配结果的第一个字符在该字符串中的位置索引。
例如利用Find函数在字符串 "Hello"中查找字符:"l",将得到"Hello"这个字符串中第一个")"字符出现的位置索引: 2。这里需要提醒读者的是:在C/C++语言中,字符串的索引是从O开始计数的。因此,这里我们可以在m s位Line中查找空格字符,得到它的位置索引,然后利用前面我们已经介绍的CString类的另一个成员函数: Left 把人名字符串截取出来,并将该字符串作为菜单项名称添加到PhoneBook子菜单下。具体的实现代码如例6-37所示,其中加灰显示的代码是新添的。
例6-37 

void CMenu2View : : OnChar(UINT nChar , UINT nRepCnt , U工NT nFlags) 
{ // TODO : Add your message handler code here and/ or call default CClientDC dc(th工s ) ; if(OxOd nChar) 
{ 
if (0 ++m_n工ndex ) 
m_Menu. CreatePopupMenu () ; 
GetParent()->GetMenu()->AppendMenu(MF_ POPUP , (UINT)m_Menu .m_hMenu, "PhoneBook"); 
GetParent()->DrawMenuBar(); 
~menu.AppendMenu(MF_STRING,lll,m_strLine.Left(m_strLine.Find(' '))); 
m_strLine.Empty() ; 
Invalidate() ; 

} 
else 

m_strLine += nChar ; 
dC.TextOut(O , O, m_strLine) ; 

CView: :OnChar(nChar, nRepCnt , nFlags); 
注:这里暂时先给新添加的这个菜单项临时取了一个ID: 111。
读者可以测试一下 Menu2程序,当程序运行后,输入几行:"人名电话号码"这样的文字,并同车,然后检查PhoneBook子菜单下的内容。将会发现输入的人名都作为菜单项
" ‘ I 207 


添加到这个子菜单下了。
下面就要实现当单击这些菜单项时,应在程序窗口中显示对应的字符串,即:人名电话号码。那么在程序中就应该将所有输入的字符串都保存起来。我们可以定义一个字符串数组来保存用户输入的所有字符串,但是因为不知道用户会输入多少个字符串,所以数组的大小无法确定。当然对于这种动态增加的数组,可以通过链表来实现,但是这种方法很麻烦,也比较复杂。 MFC为我们提供了一些非常有用的集合类,这些集合类类似于数组的功能,但它们可以很方便地动态增加和删除元素。这里我们可以利用一个名为 CStringArray的集合类,这个集合类支持 CString对象的数组。为了增加一个字符串元素,可以利用该集合类的 Add成员函数,该函数的声明具有如下的形式 : 
int Add( LPCTSTR newElement ); 
该函数的参数是一个指向常量字符串的指针 CLPCTSTR类型)。而通过 MSDN,我们可以在类 CString的成员函数中,发现这个类重载了 LPCTSTR操作符。这样的话,当我们向 CStringArray对象中添加元素时,可以直接给 Add函数的参数传递一个 CString类型的变量,编译器会自动完成转换的。当需要返回一个集合元素时,可以利用集合类的 GetAt成员函数,这个函数具有如下声明形式: 
CString GetAt( int n工 ndex ) const; 
国际: MFC提供了几个存储不同类型元素的集合类,它们的成员函数都很
类似,所以,掌握了其中的一个,其他的也就都明白了。
下面,我们就先为 CMenu2View类定义一个公有的 Cpublic类型) CStringArray类型的成员变量: m s位Array,用来保存所有输入的字符串。至于为什么将 m s位Array声明为公有的,在后面会讲述。然后在 OnChar函数中,在按下回车键后,并在 m strLi ne变量清空之前,把当前输入的一行文字增加到这个集合类变量中,即在 CMenu2View类的 OnChar函数中添加下述加灰显示的代码。 
iJtl6-38 

void CMenu2View: :OnChar(UINT nChar, UINT nRepCnt , UINT nFlags) 

. .. .. .  
m_menu .AppendMenu(MF_STRING, 111 , 
m_strLine.Left(m_strLine.Find(' ')));
 m_strArray.Add(m_strLine); 
m_strLine.Empty() ; 
Invalidate() ; 
 .  
.....  

程序的要求是当单击动态添加的人名菜单项时,程序要在窗口中显示对应的字符串:人名电话号码。这就需要首先对动态添加的菜单项进行命令捕获。这里,笔者为读者介绍一种比较有技巧的实现方法。首先,在 Menu2工程中,在资源编辑器中打开程序的菜单,
然后在【帮助】子菜单后面添加一个新的子菜单,名称可以任意,例如 "abc",接着再为它添加几个菜单项,例如 4个,本例添加菜单项的名称及其 E如表 6.3所示。
表 6.3新添菜单项的名称及 10

菜单项名称 菜单项 ID  
IDM PHONEI  
2  10M PHONE2  
3  IDM PHONE3  
4  IDM PHONE4  

品《, 
保存对资源所做的修改,然后打开 Menu2程序的 Resource.h文件,在其中可以看到如
下几行代码: 
#define工 DM 

#define IDM PHONE2

、2
叫,
aq&
#define工 DM PHONE3 

J
#define IDM PHONE4
寸,
然后利用 Class Wizard为 CMenu2View类分别添加以上这四个菜单项的命令响应函数,其中在消息列表中都选择 COMMAND消息。之后, CMenu2View类对这四个菜单项就有了四个命令响应函数。
接下来,我们在菜单资源编辑器中删除刚才新添加的子菜单 Cabc),但是将会发现它们的命令响应函数在源文件中都被保留下来了。
再回到上述例 6-38所示 CMenu2View的 OnChar函数,找到动态添加菜单项的代码,即调用 AppendMenu函数的那行代码,把其中的菜单 ID参数改成 IDM PHONEl,即修改成下面这行代码: 
m_menu.AppendMenu(MF_STRING,IDM_PHONE1, m_strLine.Left(m_strLine.Find(' '))); 
这行代码将添加 ID为 10M PHONE1的菜单项,但是,程序不能每次添加新菜单项时都使用这个菜单 E值,第二次添加时应该是 IDM_PHONE2......,直到第四次添加时应该是由M PNONE4 C因为这里是一个示例,所以本例假设最多只添加 4个菜单项)。但是如何编写程序代码让这里的 ID号由 IDM_PHONEl自动增加到 IDM_PHONE4呢?前面我们已经定义了一个变量: ID_nIndex,当每次按下回车键增加菜单项时,它的值就增1,这样,就可以利用这个变量加上 IDM_PHONEl的值来确定当前的菜单 E。当第一次按下回车键后, ID_nIndex的值是 0,加上 IDM_PHONEl后得到 IDM_PHONE1,即第一个菜单项的 ID;当第二次按下回草键后, ID nIndex的值增加为1,再加上 IDM_PHONEl C它的值为 32771)后,变成 32772,即 IOM_PHONE2,也就是第二个菜单项的 ID;……因此,利用这种方法,随着文字的输入,回车键的按下, ID_nIndex的数值不断增加,得到的菜单项 ID号也在不断变化。利用这种方式添加命令响应函数的过程很快,而且也很方便。这里,还有一些小问题需要提醒读者注意,如例 6-39所示是 CMenu2View类的头文件中消息映射函数的声明代码。
"I 209 

第6章禀单 
iJlJ 6-39 
// Generated message map functions protected : 
//({AFX_MSG(CMenu2View) 
afx_msg void OnChar(U工NT nChar , UINT nRepCnt , UINT nFlags) ; 
afx_msg void OnPhonel(); 
afx_ffisg void OnPhone2(); 
afx_ffisg void OnPhone3(); 
afx~sg void OnPhone4(); 
//}}AFX_MSG 
DECLARE_MESSAGE_MAP() 
从中可以发现VC++把我们新添的这儿个菜单命令的响应函数都放在AFX_MSG这两个注释宏之间了。其实,这样的代码也没有错误。但是为了区分这是自己手工添加的,可以把它们拿出来放在两个AFX MSG注释宏之后。
如例6-40所示是CMenu2View类源文件中消息映射表的定义代码。
例6-40 

BEG工N_MESSAGE_MAP(CMenu2View, C飞lìew) 
// ({AFX_MSG_MAP(CMenu2View) 

ON_WM_ CHAR ( )  
ON_COMMAND(工DM_PHONEl ,  OnPhonel)  
ON_COMMAND(工DM_PHONE2 ,  OnPhone2)  
ON_COMMAND(工DM_PHONE3 ,  OnPhone3)  
ON_COMMAND(工DM_PHONE4 ,  OnPhone4)  
// }}AFX_MSG_MAP  

// Standard prìntìng commands 
ON_COMMAND(工D_FILE_PR工NT, CView : :OnFilePrint) 
ON_ COMMAND(ID_FILE_ PRINT_DIRECT , CView : :OnFilePrint) 
ON_COMMAND(ID_FILE_PRINT_PREVIEW, CView : :OnFilePr工ntPreview) 

END_MESSAGE_MAP() 

可以发现VC++把刚才添加的几个命令响应映射宏都放在了两个 AFX一MSG MAP注释宏之间了。如果消息响应函数映射宏放在了这两个AFX-MSG-MAP注释宏之间的话,在ClassWizard对话框中,在Message Maps选项卡下的Memberfunctions列表中就会列出这些函数,如图6.46所示。如果消息响应函数的声明放在了这两个AFX-MSG-MAP注释宏外面的话,在 ClassWizaI吐对话框中就不会列出这些函数。与上面所说的在头文件中命令响应函数声明代码放置的位置不同,这里的映射宏代码一定要拿到两个 AFX MSG MAP注释宏之外。这是因为当 ClassWizard发现菜单项已经被删除了的时候,它就会把己为该菜单项添加的消息映射宏也删除了,这样,消息映射的三个环节中就断了一环,程序就会出错,造成不必要的麻烦。因此,这里一定要把 ClassWizard添加的几个消息映射宏拿出来,放到两个AFX_MSG_MAP注释宏之外,也就是说,Menu2程序中CMenu2View类的消息映射定义代码应该如例6-41所示。
凯灿
例 6-41 

BEGIN_MESSAGE_MAP(CMenu2View, CView) 
jj{{AFX_MSG_ MAP(CMenu2View) 
ON_WM_CHAR ( ) 
j /} } AFX_MSG_MAP 
ON_COMMAND(工 DM_PHONE1, OnPhonel) 
ON_COMMAND(工 DM_PHONE2, OnPhone2) 
ON_COMMAND(IDM_PHONE3 , OnPhone3) 
ON_COMMAND(工 DM_PHONE4, OnPhone4) 
11 Standard printing commands 
ON_COMMAND(ID_FILE_PRINT , Cview : :OnFilePrint) 
ON_COMMAND(工 D_FILE_PRINT_DIRECT, CView ::OnFilePrint) 
ON_ COMMAND(ID_ FILE_PRINT_PREVIEW, CView : : OnFilePrintPreview) 
END_MESSAGE_MAP() 

图 6.46 ClassWizard对话框

经过以上几步, Menu2程序的 CMenu2View类就有了四个动态菜单项的命令响应函数。下面我们可以为它们分别添加具体的代码,以显示相应的人名和电话号码。例如,第一个动态菜单项的命令响应函数的定义可以是如例 6-42所示的这样。
例 6-42 

void CMenu2View::O口 Pho口 el ( ) 
11 TODO : Add your command handler code here 
CClientDC dc(this) ; 
dc.TextOut(O , O,m_strArray.GetAt(O)) ; 

在该函数中,首先定义设备描述表对象: dc,然后得到字符串数组中第一个字符串(其位置索引为 0),并在窗口的 ( 0,0)位置处显示出来。其他几个命令响应函数的处理基本相同,只是获取字符串数组中字符串元素时使用的位置索引不同而己,第二个命令响应函数使用的索引是1,第三个命令响应函数使用的索引是 2,依次类推。所以对其他几个菜单命令响应函数而言,可以直接复制第一个菜单命令响应函数中的代码,然后修改索引值
........‘ I 211 

第6

就可以了。最后,读者可以运行程序井测试,将会发现 Menu2程序能够响应那些动态添加的菜单项的命令了。 

菜单命令消息

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -