【3D技术宅公社】XR数字艺术论坛  XR技术讨论 XR互动电影 定格动画

 找回密码
 立即注册

QQ登录

只需一步,快速开始

调查问卷
论坛即将给大家带来全新的技术服务,面向三围图形学、游戏、动画的全新服务论坛升级为UTF8版本后,中文用户名和用户密码中有中文的都无法登陆,请发邮件到324007255(at)QQ.com联系手动修改密码

3D技术论坛将以计算机图形学为核心,面向教育 推出国内的三维教育引擎该项目在持续研发当中,感谢大家的关注。

查看: 2171|回复: 2

使用菜单-vc++编程指南

[复制链接]
发表于 2006-1-13 11:00:32 | 显示全部楼层 |阅读模式
3.6 使用菜单 <BR><BR>  现在我们要在主窗口中加入自己的菜单。菜单编程一般分三步:<BR><BR>1.编辑菜单资源,设置菜单属性(包括菜单名和ID);<BR>2.用ClassWizard自动映射菜单消息和成员函数;<BR>3.手工编辑成员函数,加入菜单消息处理代码。<BR><BR>3.6.1 编辑菜单资源<BR><BR>  仍然使用我们前面生成的Hello程序,编辑由AppWizard自动生成的菜单资源。要编辑菜单资源:<BR><BR>(1) 选择项目工作区的ResourceView标签,切换到资源视图。<BR>(2) 选择菜单资源类型。<BR>(3) 选定菜单资源IDR_MAINFRAME,双击该项或单击鼠标右键然后在弹出菜单中选择Open选项。Visual Studio将弹出菜单编辑窗口,显示菜单资源IDR_MAINFRAME,其中IDR_MAINFRAME是由AppWizard在创建该程序时自动生成的。<BR>(4) 编辑当前菜单<BR><BR>  要删除某个菜单项或弹出菜单,可用鼠标单击该菜单或用上下光标键来回选择,然后按Del键删除;要插入新菜单项,可选定窗口中的空白菜单框后按回车(或直接用鼠标双击该空白框),Visual Studio弹出Properties(属性)对话框,如图3-11所示。属性对话框用于输入菜单项的标题、标识符、菜单项在状态栏上显示的提示(Prompt),并为该菜单提供属性调整。也可以在选择一个已有的菜单项时按Ins键,以在该菜单项上方插入一个空白菜单项,然后双击该菜单项进行编辑。要插入一个分隔线,只需将菜单项的Seperator属性打开即可。<BR>  Visual Studio支持鼠标拖曳调整菜单项位置。要调整菜单项位置,只需要选中某菜单项并将其拖至适当位置即可。<BR>&gt;<BR><BR>如上图,我们首先在Edit和View之间加入一个弹出菜单:用鼠标单击View菜单,按Ins键插入一个空白菜单项,双击该空白框弹出其属性对话框。在菜单属性栏输入“&amp;Test”字样。然后在Test弹出菜单下加入以下四个菜单项,并在&amp;Say Hello菜单下加入一个分隔符。菜单项属性设置如下表:<BR><BR>菜单名 菜单ID 菜单提示(Prompt) <BR>&amp;Say Hello ID_SAY_HELLO Say hello to you! <BR>&amp;Red ID_SELECT_RED The color is red. <BR>&amp;Blue ID_SELECT_BLUE The color is blue. <BR>&amp;Yellow ID_SELECT_YELLOW The color is yellow. <BR><BR>提示:如果菜单中要使用中文,则除了在菜单名一项中输入中文外,还要将菜单资源的语言属性设置为中文。方法是:鼠标右键单击资源视图的菜单资源IDR_MAINFRAME,弹出快捷菜单,选择Properties,弹出整个菜单资源的属性对话框,如图3-12所示。在Languages下拉列表框中选择Chinese (P.R.C.)。这样以后菜单就可以正确使用和显示中文了。如果其他资源如对话框或字符串要使用中文,也要将该资源的语言属性改为Chinese(P.R.C)。 <BR>&gt;<BR>现在关闭菜单编辑器窗口。我们要为Say Hello菜单增加一个加速键CTRL+H。要编辑加速键,选择Accelerator资源类型,双击打开IDR_MAINFRAME加速键资源。要删除加速键,可以直接按Del键。要增加加速键,可以按Ins键,弹出加速键属性对话框。在ID下拉列表框中选择ID_SAY_HELLO,在Key一栏中输入H,完成加速键设置。关闭加速键编辑窗口。<BR><BR>3.6.2 用ClassWizard自动映射菜单消息和成员函数<BR><BR>  现在我们用ClassWizard为上面创建的几个菜单生成和映射消息处理成员函数。在此之前我们首先介绍一下ClassWizard的用法。<BR><BR>用ClassWizard管理类和Windows消息<BR><BR>  ClassWizard有助于创建Windows消息和命令处理函数、创建和管理类、创建类成员变量、创建OLE Automation的方法和属性、创建数据库类以及其他一些工作。<BR>  ClassWizard也有助于覆盖MFC类中的虚函数。先选类,再选择需要覆盖的虚函数。该过程的其余部分与消息处理是类似的。<BR><BR>启动ClassWizard应用程序<BR><BR>  从View菜单或源程序编辑窗口右键菜单中选择ClassWizard(快捷键:Ctrl +W),Developer Studio将弹出MFC ClassWizard对话框。该对话框包含几个标签页,提供以下选项:<BR><BR>Message Maps:它管理消息和成员函数之间的映射关系。<BR><BR>Member Variables:它可以让用户加进一些数据成员,以便和各种控制进行数据交换。<BR><BR>Automations:它提供了各种特性支持OLE2.0,包括为OLE Automation增加属性、方法以及处理事件。<BR><BR>ActiveX Events:为ActiveX控件增加属性、方法以及为ActiveX控件事件增加处理函数。<BR><BR>Class Info:它可以让用户创建新类,以便支持对话框和各种可视类(包括控制、窗口等)。还可以从类库文件导入类到当前工程中。<BR><BR>  在这一章里,我们只用到Message Maps这一页,因此我们在这里只介绍Message Maps的使用。<BR><BR>Message Maps选项<BR><BR>  可以让用户加入成员函数来处理消息,删除成员函数以及对成员函数进行编辑。<BR><BR>Message Maps页包括如下控制选项:<BR><BR> <BR><BR>rojects组合框:允许用户选择当前工作区中包含的工程。<BR><BR>Class Name组合框:允许用户选择当前工程中的类。<BR><BR>Objects IDs列表框:列出当前选中的类名及相关的ID。对窗口和视来说,这些ID为菜单标识符;对对话框来说,这些ID为控制框的ID。<BR><BR>Messages列表框:列出当前所选类的可重载的虚方法以及可接收到的消息。<BR><BR>Member Functions列表框:列出ClassName组合框中当前所选的项中所包含的所有成员函数。用户可以增加、删除成员函数,也可以对成员函数进行编辑。<BR><BR>Add Class...按钮:它允许用户往工程里添加新类。在按钮右边有一个向下的小箭头,表明按此按钮将弹出一个菜单。菜单包含两项:New...可以新建一个类;From a type Lib用于从一个类库中导入类。<BR><BR>Add Function按钮:它允许用户往Member Functions列表框中加进一个新的消息处理成员函数,该新增成员函数被用来响应Message Maps列表中当前所选中的消息。<BR><BR>Delete Function按钮:用于删除Member Functions列表框中所选中的项。<BR><BR>Edit Code按钮:它允许用户对Member Functions中所选中的项进行编辑,此时Visual Studio 将关闭MFC ClassWizard对话框,并打开相应文件,并将光标定位在函数定义的开头处。<BR>&gt;<BR>现在我们就利用ClassWizard为Hello程序增加菜单消息和成员函数的映射。在View菜单下选择ClassWizard,弹出MFC ClassWizard对话框。选择Message Maps页,在Class Name下拉列表中选择CMainFrame类。在Object IDs中选择ID_SAY_HELLO,在Messages栏中双击COMMAND,弹出Add Member Function对话框。对话框中给出缺省的成员函数OnSayHello,按OK接收缺省的成员函数名。此时OnSayHello 成员函数就出现在Member Functions列表框中,后面跟所映射的消息,如图3-13所示。列表框中开头的字母W表示窗口消息,V表示可重载的虚方法(Virtual Method)。如此,依次为ID_SELECT_BLUE、ID_SELECT_RED、ID_SELECT_YELLOW增加消息处理成员函数OnSelectBlue、OnSelectRed、OnSelectYellow。然后双击Member Functions列表中的OnSayHello,编辑OnSayHello成员函数。<BR>
 楼主| 发表于 2006-1-13 11:01:00 | 显示全部楼层
<H1>手工添加代码-使用菜单</H1>
<>3.6.3 手工添加代码<BR><BR>在OnSayHello成员函数体中加入语句。<BR><BR>void CMainFrame::OnSayHello()<BR><BR>{<BR><BR>AfxMessageBox(“Hello!”);<BR><BR>}<BR><BR>消息框函数<BR><BR>AfxMessageBox用来弹出一个消息框,它的函数原型有两种版本:<BR><BR>int AfxMessageBox( LPCTSTR lpszText, UINT nType = MB_OK, UINT nIDHelp = 0 );<BR><BR> <BR><BR>int AFXAPI AfxMessageBox( UINT nIDPrompt, UINT nType = MB_OK, UINT nIDHelp = (UINT) –1 );<BR><BR>  在第一种形式中,lpszText表示在消息框内部显示的文本,消息框的标题为应用程序的可执行文件名(如Hello)。在第二种形式中,nIDPrompt为要显示的文本字符串在字符串表中的ID。函数调用时会自动从字符串表中载入字符串并显示在消息框中。nType为消息框中显示的按钮风格和图标风格的组合,可以采用|(或)操作符组合各种风格。<BR><BR>按钮风格<BR><BR>MB_ABORTRETRYIGNORE 消息框中显示Abort、Retry、Ignore按钮<BR><BR>MB_OK 显示OK按钮<BR><BR>MB_OKCANCEL 显示OK、Cancel按钮<BR><BR>MB_RETRYCANCEL 显示Retry、Cancel按钮<BR><BR>MB_YESNO 显示Yes、No按钮<BR><BR>MB_YESNOCANCEL 显示Yes、No、Cancel按钮<BR><BR>图标风格<BR><BR>MB_ICONINFORMATION 显示一个i图标,表示提示<BR><BR>MB_ICONEXCLAMATION 显示一个惊叹号,表示警告<BR><BR>MB_ICONSTOP 显示手形图标,表示警告或严重错误<BR><BR>MB_ICONQUESTION 显示问号图标,表示疑问<BR><BR>  比如,要在消息框中显示一个问号、一个“Yes”按钮、一个“No”按钮,可以以下面的方式调用AfxMessageBox。<BR><BR>AfxMessageBox(“Are you sure?”,MB_YESNO|MB_ICONQUESTION);<BR><BR>还有一个与AfxMessageBox类似的函数MessageBox,它是CWnd的类成员函数:<BR><BR>int MessageBox( LPCTSTR lpszText,LPCTSTR lpszCaption = NULL,<BR><BR>UINT nType = MB_OK );<BR><BR>  与AfxMessageBox不同的是,它多了一个lpszCaption参数,从名字上就可以推断出它表示消息框的标题,这样就可以设置消息框的标题,而不必采用可执行文件名作为标题了。<BR>  两个函数的区别:AfxMessageBox比MessageBox简单一些,因为它是一个全局函数所以不需要对应的一个窗口类,但是不能控制消息框标题,常用于调试程序时的内部数据输出或警告;MessageBox比较正式,常用在要提交的应用程序版本中,可以控制标题内容而不必采用含义不明的可执行文件名为标题。<BR>  现在再来编写OnSelectRed、OnSelectBlue、OnSelectYellow三个函数。首先我们双击CMainFrame类名,在MainFrm.h中加入数据成员,如下所示:<BR></P>
<>class CMainFrame:public CFrameWnd{<BR><BR>...<BR><BR>// Attributes<BR><BR>public:<BR><BR><BR>int m_nColor;<BR><BR>enum{RED=0,BLUE=1,YELLOW=2};<BR><BR>...<BR><BR>}</P>
<><BR>  注意我们这里使用了匈牙利命名法,建议读者也采用这种命名方法,以便提高程序可读性。加入数据成员后,还要对它进行初始化,初始化工作在CMainFrame()构造函数中完成。<BR></P>
<>CMainFrame::CMainFrame()<BR><BR>{<BR><BR>m_nColor=RED;<BR><BR>}</P>
<><BR>OnSelectRed、OnSelectBlue、OnSelectYellow三个函数修改后如清单3.4:<BR><BR>清单3.4<BR></P>
<>void CMainFrame()::OnSelectRed()<BR><BR>{<BR><BR> <BR><BR>m_nColor=RED;<BR><BR>SayColor();<BR><BR>}<BR><BR>void CMainFrame()::OnSelectBlue()<BR><BR>{<BR><BR>m_nColor=BLUE;<BR><BR>SayColor();<BR><BR>}<BR><BR>void CMainFrame()::OnSelectYellow()<BR><BR>{<BR><BR>m_nColor=YELLOW;<BR><BR>SayColor();<BR><BR>}</P>
<><BR>然后在MainFrm.h中加入SayColor()函数的声明:<BR><BR>//Operations<BR><BR>public:<BR><BR>void SayColor();<BR><BR>在MainFrm.cpp中,在OnSelectYellow()成员函数后面,手工加入SayColor()函数的定义。<BR><BR></P>
<>void CMainFrame::SayColor()<BR><BR>{<BR><BR>switch(m_nColor)<BR><BR>{<BR><BR>case RED:<BR><BR>AfxMessageBox(“Color is red!”);<BR><BR>break;<BR><BR>case BLUE:<BR><BR>AfxMessageBox(“Color is blue!”);<BR><BR>break;<BR><BR>case YELLOW:<BR><BR>AfxMessageBox(“Color is yellow!”);<BR><BR>break;<BR><BR>}<BR><BR>}</P>
<><BR>  这样,当我们选择颜色时,就会显示不同的消息框显示当前选择的颜色。但是用消息框显示当前选中的颜色似乎太繁琐了一些。我们在使用WORD编写文档时,注意到在选择不同的视图时,在视图菜单名前显示一个点,表明这是当前选择的视图。我们是否也可以这么做?回答是肯定的。要实现这一功能,就要使用MFC框架的更新命令用户接口消息机制。<BR></P>
 楼主| 发表于 2006-1-13 11:01:31 | 显示全部楼层
<H1>更新命令用户接口(UI)消息</H1>
<>3.7 更新命令用户接口(UI)消息<BR><BR>  一般情况下,菜单项和工具条按钮都不止一种状态,我们经常需要根据应用的内部状态来对菜单项和工具条按钮作相应的改变。例如,在我们没有选择任何内容时,编辑菜单下的“复制”、“剪切”等菜单是无效的(灰色显示)。有时,我们还会看到,在菜单项旁边可能还会有检查标记,表示它是选中的还是不选中的。比如,在Word的视图菜单下,根据用户所选的显示模式,在“普通”、“大纲”、“页面”“主控文档”前会出现一个点符号,标识当前所选的视图方式。工具条也有类似的情形,如果按钮不可用也可以被置成无效,或者可以被选中。<BR>  如果我们采用SDK来编程,那么我们就要跟踪与这些状态相关的变量所有可能发生变化的地方,并根据可能发生的变化作相应的处理。这样的工作非常复杂且容易遗漏。为此,MFC应用程序框架引入了更新命令用户接口消息来简化这一工作。<BR>  在ClassWizard的Message Map页中,如果我们选择一个菜单ID,在Messages列表框中就会出现两项:<BR><BR>COMMAND<BR><BR>UPDATE_COMMAND_UI<BR><BR>  其中UPDATE_COMMAND_UI就是更新命令用户接口消息,专门用于处理菜单项和工具条按钮的更新。每一个菜单命令都对应于一个更新命令用户接口消息。可以为更新命令用户接口消息编写消息处理函数来处理用户接口(包括菜单和工具条按钮)的更新。如果一条命令有多个用户接口对象(比如一个菜单项和一个工具条按钮),两者都被发送给同一个处理函数。这样,对于所有等价的用户接口对象来说,可以把用户接口更新代码封装在同一地方。<BR><BR>3.7.1用户接口更新原理<BR><BR>  为了理解用户接口更新机制,我们来看一下应用框架是如何实现用户接口更新的。当我们选择Edit菜单时,将产生一条WM_INITMENUPOPUP消息。框架的更新机制将在菜单拉下之前集体更新所有的项,然后再显示该菜单。<BR>  为了更新所有的菜单项,应用框架按标准的命令发送路线把该弹出式菜单中的所有菜单项的更新命令都发送出去。通过匹配命令和适当的消息映射条目(形式为ON_UPDATE_COMMAND_UI),并调用相应的更新处理器函数,就可以更新任何菜单项。比如,Edit菜单下有Undo、Cut、Copy、Paste等四个菜单项,就要发送四条用户接口更新命令。如果菜单项的命令ID有一个更新处理器,它就会被调用进行更新;如果不存在,则框架检查该命令ID的处理函数是否存在,并根据需要使菜单有效或无效。<BR>  如果在命令发送期间找不到对应于该命令的ON_UPDATE_COMMAND_UI项,那么框架就检查是否存在一个命令的ON_COMMAND项,如果存在,则使该菜单有效,否则就使该菜单无效(灰化)。这种更新机制仅适用于弹出式菜单,对于顶层菜单象File和Edit菜单,就不能使用这种更新机制。<BR>  按钮的命令更新机制与菜单的命令接口更新机制类似,只是工具条按钮的命令接口更新在空闲循环时完成。有关工具条按钮的接口更新机制,我们将在下一章“工具条和状态栏”中作详细介绍。<BR><BR>3.7.2 用户接口更新机制编程<BR><BR>  当框架给处理函数发送更新命令时,它给处理函数传递一个指向CCmdUI对象的指针。这个对象包含了相应的菜单项或工具条按钮的指针。更新处理函数利用该指针调用菜单项或工具条的命令接口函数来更新用户接口对象(包括灰化,使,使能,选中菜单项和工具条按钮等)。下面我们使用前面的例子演示如何使用用户接口更新机制:<BR><BR>1.按Ctrl+W激活ClassWizard,选择Message Map选项页。<BR>2.在Object IDs列表中选择 ID_SELECT_RED,在Messages列表中双击ON_UPDATE _COMMAND_UI条目,弹出Add Member Function对话框,缺省函数名为OnUpdateSelect Red,按OK按钮接收此函数名。OnUpdateSelectRed成员函数名就出现在Member Functions列表中。依次给ID_SELECT_BLUE、ID_SELECT_YELLOW增加OnUpdateSelectBlue和OnUpdateSelectYellow命令接口更新成员函数。<BR>3.现在手工编辑刚才生成的成员函数,修改后形式如清单3.5所示:<BR><BR>清单3.5<BR></P>
<>void CMainFrame::OnUpdateSelectBlue(CCmdUI* pCmdUI) <BR><BR>{<BR><BR>// TODO: Add your command update UI handler code here<BR><BR> <BR><BR>pCmdUI-&gt;SetCheck(m_nColor==BLUE);<BR><BR>}<BR><BR>void CMainFrame::OnUpdateSelectRed(CCmdUI* pCmdUI) <BR><BR>{<BR><BR>// TODO: Add your command update UI handler code here<BR><BR>pCmdUI-&gt;SetCheck(m_nColor==RED);<BR><BR>}<BR><BR>void CMainFrame::OnUpdateSelectYellow(CCmdUI* pCmdUI) <BR><BR>{<BR><BR>// TODO: Add your command update UI handler code here<BR><BR> <BR><BR>pCmdUI-&gt;SetCheck(m_nColor==YELLOW);<BR><BR>}</P>
<><BR>  现在编译运行Hello程序。当我们打开Test菜单时,如图3-14所示,在Red菜单项前已经有了一个对号。因为前面在CMainFrame构造函数中,我们已经将颜色初始化为RED。如果选择Blue,下次打开Test菜单时,在Blue菜单前就会有一个对号,而Red前面的对号则没有了。<BR>&gt;<BR>类似的,要根据某个状态开关菜单,也可以为菜单生成命令接口更新成员函数。比如,在Edit菜单中,如果当前剪贴板没有内容,Paste(粘贴)菜单应当设为无效,程序可以这么写:<BR></P>
<>void CMainFrame::OnUpdateEditPaste(CCmdUI* pCmdUI)<BR><BR>{<BR><BR>pCmdUI-&gt;Enable(!IsClipboardEmpty());<BR><BR>}</P>
<><BR>  其中IsClipboardEmtpy()是读者自己编写的函数,用于判断剪贴板中是否有内容<BR></P>
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

手机版|小黑屋|3D数字艺术论坛 ( 沪ICP备14023054号 )

GMT+8, 2024-6-3 21:40

Powered by Discuz! X3.4

Copyright © 2001-2020, Tencent Cloud.

快速回复 返回顶部 返回列表