【vc】6_菜 单

1、菜单命令响应函数:

  提示:MFC都是采用大写字母来标识资源ID号的;为了区分资源类型,一般遵循这样一个原则:在“ID”字符串后加上一个标识资源类型的字母。例:菜单资源(Menu):ID_Mxxx;光标资源(Cursor):ID_Cxxx;图标资源(Icon):ID_Ixxx等;

2、菜单命令的路由:

  程序类对菜单命令的响应顺序:视类、文档类、框架类、应用程序类

    xxxView --> xxxDoc --> xxxFrame --> xxxApp(可以通过调试验证,注意:CxxxApp类 和 CxxxDoc类 都不是从CWnd类派生的,故都没有MessageBox成员函数,所以要使用全局的MessageBox函数,或者使用应用程序框架的函数:AfxMessageBox)

int AfxMessageBox( LPCTSTR lpszText, UINT nType = MB_OK, UINT nIDHelp = 0 );

  Windows消息的分类

    ·标准消息 除WM_COMMAND之外,所有以WM_开头的消息。 从CWnd派生的类,都可以接收到这类消息。

    ·命令消息 来自菜单、加速键或工具栏按钮的消息。这类消息都以WM_COMMAND呈现。在MFC中,通过菜单项的标识(ID)来区分不同的命令消息;在SDK中,通过消息的wParam参数识别。 从CCmdTarget派生的类,都可以接收到这类消息。

    ·通告消息 由控件产生的消息,例如,按钮的单击,列表框的选择等均产生此类消息,为的是向其父窗口(通常是对话框)通知事件的发生。这类消息也是以WM_COMMAND形式呈现。 从CCmdTarget派生的类,都可以接收到这类消息。

  CWnd类派生于 CCmdTarget类;即:凡是从CWnd派生的类,他们既可以接收标准消息,也可以接收命令消息和通告消息。而对于那些从CCmdTarget派生的类,则只能接收命令消息和通告消息,不能接收标准消息。(文档类、视图类 派生于 CCmdTarget类)

  **菜单命令的路由

    菜单命令消息响应函数的映射与“4_简单绘图”中介绍的标准消息的映射是一样的,只是消息命令使用的是ON_COMMAND宏。但是:命令消息和标准消息的路由过程还是有区别的。

提示:WindowProc函数是CWnd类的一个成员函数。

3菜单的结构

  整个楼房对应于程序中的菜单栏,楼房的每一层对应于菜单栏上的子菜单(如:文件、编辑、查看、帮助等菜单对象),而房间对应于菜单项。

  注意:分隔栏在(子)菜单中是占据索引位置的。

  程序的主菜单属于框架窗口,所以需要在框架类窗口创建完成之后再去访问菜单对象。可以在框架类(CMainFrame类)的OnCreate函数的最后(return之前)添加对菜单功能操作的代码。

//CWnd::GetMenu
CMenu* GetMenu( ) const; 

  ·功能:在框架窗口中获得指向菜单栏的指针;CMenu类是一个MFC类,是Windows菜单句柄HMENU的一个封装,提供一些与菜单操作有关的成员函数,例如:菜单的创建、更新和销毁等,还可以获得一个菜单的子菜单,如下:

//CMenu::GetSubMenu
CMenu* GetSubMenu( int nPos ) const;

  ·功能:获取一个菜单的子菜单;

  ·nPos:指定子菜单的索引号;

  ·返回一个指向CMenu对象的指针,该函数返回值所指向的对象与CWnd类的GetMenu函数的返回值所指向的对象不一样;GetMenu函数返回的是指向程序菜单栏对象的指针,而GetSubMenu成员函数返回的是由参数nPos指定的子菜单的指针。

  

  注意:GetMenu函数是CWnd类的成员函数,而GetSubMenu函数是CMenu的成员函数。

//CMenu::CheckMenuItem
UINT CheckMenuItem( UINT nIDCheckItem, UINT nCheck ); 

  ·功能:为菜单项添加一个标记,或者移除菜单项的标记;

  ·nIDCheckItem:指定需要处理的菜单项,它的取值由第二个参数决定。

  ·nCheck:指定怎样设置菜单项,以及如何定位该菜单项的位置;取值可以是:MFCHECKED 或 MF_UNCHECKED 与 MF_POSITION 或 MF_BYCOMMAND的组合;

如: GetMenu()->GetSubMenu(0)->ChechMenuItem(0, MF_BYPOSITION | MF_COMMOD); 此为位置访问菜单项,也可用菜单标识访问。

//CMenu::SetDefaultItem
BOOL SetDefaultItem( UINT uItem, BOOL fByPos = FALSE );

  ·作用:设置默认菜单项;

  ·uItem:取值由第二个参数决定;可以是新的默认喜爱单项的表示或位置索引,值为-1,表明没有默认菜单项。

  ·fByPos:值为FALSE,表明第一个参数是菜单项标识,否则是菜单项位置索引;

  ·一个子菜单只有一个默认菜单项;

图形标记菜单:

//CMenu::SetMenuItemBitmaps
BOOL SetMenuItemBitmaps( UINT nPosition, UINT nFlags, const CBitmap* pBmpUnchecked, const CBitmap* pBmpChecked );

  ·作用:将指定的位图与菜单项关联起来(菜单项前面有小图标);

  ·第一个参数(nPosition)的取值也是由第二个参数(nFlags)的值决定;

  ·第三个参数:指定当取消菜单项选中状态时的位图,

  ·第四个参数:指定选中菜单项时显示的位图(当然可以都指定同一个位图,也可以指定不同的位图);

  注意:bitmap是全局变量还是局部变量这很关键,它们的作用周期不同,会导致不一样的结果。

int GetSystemMetrics(
  int nIndex   // system metric or configuration setting
);

  ·作用:用来指定希望获取那部分系统信息;

  ·nIndex:当值为SM_CXMENUCHECK或SM_CYMENUCHECK时,该函数将获取标记菜单项上标记图形的默认尺寸,前者是获得标记图形的宽度,后者是获得标记图形的高度(还有很多其他的取值,参见MSND)。

禁用菜单项:

//CMenu::EnableMenuItem
UINT EnableMenuItem( UINT nIDEnableItem, UINT nEnable );
// NOTE: m_bAutoMenuEnable is set to FALSE in the constructor of
// CMainFrame so no ON_UPDATE_COMMAND_UI or ON_COMMAND handlers are
// needed, and CMenu::EnableMenuItem() will work as expected. 

  ·作用:设置菜单项的状态:能够使用、禁用或变灰显示。

  ·第一个参数有第二个参数决定。后者可以是MF_DISABLED, MF_ENABLED 或 MF_GRAYED 与 MF_BYCOMMAND(指定第一个参数是菜单项的标识ID) 或 MF_BYPOSITION(指定第一个参数是菜单项的位置索引) 的组合。

  ·提示信息:一旦在CMainFrame类的构造函数中把成员变量m_bAutoMenuEnable设置为FALSE后,就不需要对ON_UPDATE_COMMAND_UI 或 ON_COMMAND 消息进行响应处理了,CMenu类的EnableMenuItem函数将能够正常工作。(默认情况下,所有菜单项的更新都是由MFC的命令更新机制完成的。如果我们想自己更改菜单项的状态,那就必须先把 m_bAutoMenuEnable 变量设置为FALSE,之后,我们自己对相爱但想的状态更新才能起作用)

   CMainFrame::CMainFrame()
  {

    //TODO:ADD menber initialization code here
    m_bAutoMenuEnable = FALSE;
  }

  ·将m_bAutoMenuEnable设置为FALSE后,MFC就不再利用它的菜单命令更新机制去判断哪个菜单可以使用,那个菜单不能够使用,所以其也就不能根据菜单项的状态以不同的外观来显示;而菜单能否使用这些判断操作,就需要我们自己去完成了。

移除和装载菜单:

//CWnd::SetMenu
BOOL SetMenu( CMenu* pMenu );

  ·pMenu:指向一个新菜单对象。值为NULL,则当前菜单就被移除了。

  

  在编程中,除了使用MFC自动创建的IDR_MAINFRAME菜单以外,还可以自己创建一个菜单资源并加载,然后调用SetMenu函数,从而使程序的菜单编程自己定义的这个菜单;通过这种方式,可以实现动态更换程序菜单的功能

  提示:在设置窗口菜单是,如果定义的是局部菜单对象,则一定要在调用SetMenu函数设置窗口菜单之后,立即调用菜单对象的Detach函数将菜单句柄与菜单对象分离。

//CMenu::Detach
HMENU Detach( );

  ·功能:把菜单句柄与这个菜单对象(局部变量)分离。在“SetMenu(xxx);” 后使用;(SetMenu函数会把窗口的菜单设置为器参数指定的新菜单,到时窗口重绘,以反映菜单的这种变化,同时也将该菜单对象的所有权交由给窗口对象。而税后的Detach函数会把菜单句柄与这个菜单对象分离,这样当这个局部菜单对象的声明周期结束时,它不会去销毁一个它不再具有拥有权的菜单)

MFC菜单命令的更新机制

  利用MFC编程时,菜单项状态的维护依赖与CN_UPDATE_COMMAND_UI消息,谁捕获CN_UPDATE_COMMAND_UI消息,MFC就在其中那个创建一个CCmdUI对象。(我们可以通过手工,或利用ClassWizard在消息映射中添加ON_UPDATE_COMMAND_UI宏来捕获CN_UPDATE_COMMAND_UI消息)

                 图示  为剪切菜单项增加UPDATE_COMMAND_UI消息处理函数

BEGIN_MESSAGE_MAP(CMainFrame, CFrameWnd)
    //{{AFX_MSG_MAP(CMainFrame)
    ON_WM_CREATE()
    ON_COMMAND(IDM_TEST, OnTest)
    ON_UPDATE_COMMAND_UI(ID_EDIT_CUT, OnUpdateEditCut)//*消息映射机制自动添加的xxx宏*该宏是用来捕获CN_UPDATE_COMMAND_UI消息的
    //}}AFX_MSG_MAP
END_MESSAGE_MAP()

当程序框架捕获到了CN_UPDATE_COMMAND_UI消息后,最终还是交由该消息的响应函数来处理,例如本例中的OnUpdateEditCut函数:

void CMainFrame::OnUpdateEditCut(CCmdUI* pCmdUI)
{
    // TODO: Add your command update UI handler code here

}

  ·CCmdUI指针类型的参数:利用CCmdUI类,可以决定一个菜单项是否可以使用、是否有标记,还可以改变菜单项的文本。(UI(User Interface):用户接口;菜单项 就是一个用户接口)

  提示:CN_UPDATE_COMMAND_UI消息的响应只能应用于菜单项,不能应用与永久显示的顶级菜单(即弹出式菜单)项目。

MFC在后台的所做的工作是:当要显示菜单时,操作系统发出WM_INITMENUPOPUP消息,然后有程序窗口的基类如CFrameWnd接管。它会创建一个CCmdUI对象,并与程序的第一个菜单项相关联,调用该对象的一个成员函数DoUpdate()。这个函数发出CN_UPDATE_COMMAND_UI消息,这条消息带有一个指向CCmdUI对象的指针。这时,系统会判断是否存在一个ON_UPDATE_COMMAND_UI宏去捕获这个菜单项消息。如果找到这样一个宏,就调用响应的消息响应函数进行处理,在这个函数中,可以利用传递过来的CCmdUI对象去调用响应的函数,是该菜单项可以使用,或禁用该菜单项。当更新完第一个菜单项后,同一个CCmdUI对象就设置为与第二个菜单项相关联,以此顺序进行,知道完成所有菜单项的处理。这就是MFC命令更新机制

  利用MFC提供的命令更新机制,在程序中实现菜单项的可用或机制功能时就变得很简单了。我们只需要捕获UPDATE_COMMAND_UI消息,在该消息的响应函数中调用CCmdUI对象的相应函数,如:Enable、SetCheck、或SetText函数,就可以分别实现菜单项可用或禁用、设置标志菜单,或者设置菜单项的文本这些功能。

//CCmdUI::xxx
virtual void Enable( BOOL bOn = TRUE );
virtual void SetCheck( int nCheck = 1 );
virtual void SetRadio( BOOL bOn = TRUE );
virtual void SetText( LPCTSTR lpszText );
void ContinueRouting( );

如果要把工具栏上的一个工具按钮与菜单栏中的某个菜单项相关联,只要将他们的ID设置为同一个标识就可以了。

计算菜单项索引时,一定要把分隔栏菜单项计算在内。

综上:如果要在程序中设置某个菜单系那个的状态,首先通过ClassWizard为这个菜单项添加UPDATE_COMMAND_UI消息响应函数,然后在这个函数中进行状态的设置即可。

快捷菜单:

//CMenu::TrackPopupMenu
BOOL TrackPopupMenu( UINT nFlags, int x, int y, CWnd* pWnd, LPCRECT lpRect = NULL );

  ·作用:显示一个快捷菜单。

快捷菜单创建的步骤

  (1)为Menu程序增加一个新的菜单资源(Menu1)。然后打开菜单资源添加菜单项。如:

  (2)给CMenuView类添加WM_RBUTTONDOWN消息响应函数。(如果是在鼠标右键单击窗口时显示快捷菜单,那么就应该捕获这个消息)

void CMenuView::OnRButtonDown(UINT nFlags, CPoint point)
{
    // TODO: Add your message handler code here and/or call default
    CMenu menu;
    menu.LoadMenu (IDR_MENU1);
    CMenu* pPopup = menu.GetSubMenu(0);

        ClientToScreen(&point);//左边转换,把客户区坐标转换为屏幕坐标
    pPopup->TrackPopupMenu(TPM_LEFTALIGN | TPM_RIGHTBUTTON, point.x, point.y, this);//注意:this的不同,就有不同的响应

    CView::OnRButtonDown(nFlags, point);
}

  (3)为Menu程序添加快捷菜单上个菜单项命令的响应函数。

  提示:对于快捷菜单,如果将其拥有者窗口设置为框架类窗口,则框架类窗口才能有机会获得对该快捷菜单中的菜单项的命令响应,否则,就只能有视类窗口做出响应。

动态菜单操作

  未完待续···

【vc】6_菜 单,布布扣,bubuko.com

时间: 2024-11-16 06:58:51

【vc】6_菜 单的相关文章

VC POST表单——登录验证新浪邮箱

1.本机环境: Windows XP SP3.ADSL 2.开发工具: WildPackets OmniPeek V5.1.4 Visual C++ 6.0 IE6.0 FlexEdit V2.3.1871 如果觉得OmniPeek文件太大不方面下载的朋友,可以使用开源的简易抓包分析工具,先登录codeproject,再单击此处开始下载或邮件给我索取源码 ([email protected] 或 [email protected]) 注意:如果没有登录codeproject的话是无法下载的,你可

Delphi -- 创建 桌面、发送到...、快速启动栏、开始菜单、程序菜单、右键菜 单

{================================================================= 功 能: 创建 桌面.发送到....快速启动栏.开始菜单.程序菜单.右键菜单 快捷方式 参 数: FileName : 快捷方式执行文件名 Description : 快捷方式描述信息 Arguements : 快捷方式执行参数 ShowName : 快捷方式显示名称 Location : 快捷方式类别 id : 需设置状态的队列号(255 为设置) Create

VC提交网页表单(一共八篇)

VC提交网页表单-自动评论留言(1)http://blog.csdn.net/wangningyu/article/details/4526357VC提交网页表单-自动评论留言(2)http://blog.csdn.net/wangningyu/article/details/4526551 HTTP协议学习笔记http://blog.csdn.net/wangningyu/article/details/4541556HTTP Post Using Chttp://blog.csdn.net/

VC常用小知识

(1) 如何通过代码获得应用程序主窗口的 指针?主窗口的 指针保存在CWinThread::m_pMainWnd中,调用AfxGetMainWnd实现.AfxGetMainWnd() ->ShowWindow(SW_SHOWMAXMIZED)//使程序最大化. (2) 确定应用程序的路径Use GetModuleFileName 获得应用程序的路径,然后去掉可执行文件名.Example:TCHARexeFullPath[MAX_PATH] // MAX_PATH在API中定义了吧,好象是128G

在单文档中显示我的第一个对话框

在单文档中显示我的第一个对话框 (2010-04-19 21:19:50) 转载▼ 标签: it   今天编写了在单文档中创建对话框以及调用对话框的代码,收获很多: 1:OnInitDialog函数的加载问题尤其是在VS上的加载:(这一点花了很长时间才查到资料) OnInitDialog()函数是个virtual(虚函数),在它的类中用添加虚 函数的方法,会发现添加的虚函数里面没有这个函数,而这个 OnInitDialog函数是很有用的,在一般的添加进去的对话框的类中 是不会有这个函数的,必须手

VC中常见的108个问题

(1) 如何通过代码获得应用程序主窗口的 指针? 主窗口的 指针保存在CWinThread::m_pMainWnd中,调用AfxGetMainWnd实现. AfxGetMainWnd() ->ShowWindow(SW_SHOWMAXMIZED) //使程序最大化. (2) 确定应用程序的路径 Use GetModuleFileName 获得应用程序的路径,然后去掉可执行文件名. Example: TCHAR exeFullPath[MAX_PATH] // MAX_PATH在API中定义了吧,

VC编译连接选项详解(转)

大家可能一直在用VC开发软件,但是对于这个编译器却未必很了解.原因是多方面的.大多数情况下,我们只停留在“使用”它,而不会想去“了解”它.因为它只是一个工具,我们宁可把更多的精力放在C++语言和软件设计上.我们习惯于这样一种“模式”:建立一个项目,然后写代码,然后编译,反反复复调试.但是,所谓:“公欲善其事,必先利其器”.如果我们精于VC开发环境,我们是不是能够做得更加游刃有余呢? VC的处理流程,大致分为两步:编译和连接.源文件通过编译生成了.obj文件:所有.obj文件和.lib文件通过连接

经纬Zhang英拉垫背的企业家VC没有到这种地步这么卑鄙

经纬的合伙人张颖前不久发了一篇名为<泡沫就在那里------致经纬系CEO的一封信>,这篇文章所提到的泡沫论在业界引发了强烈的反响,随后有评论觉得,这明明是VC(风险投资)们自己的危机,为何要拉创业者垫背,似乎对张颖的观点非常不屑.只是笔者想说的是,VC还没下贱到要拉创业者垫背的地步,这怎么说呢? 事实上这并非张颖个人的看法,美国风险投资家.网景公司创始人马克?安德森(Marc Andreessen)一直以来都否认当今的科技市场存在泡沫,但前不久他却对科技行业的现状发出警告.他在Twitter

VC编译连接选项详解

VC编译连接选项详解 大家可能一直在用VC开发软件,但是对于这个编译器却未必很了解.原因是多方面的.大多数情况下,我们只停留在"使用"它,而不会想去"了解"它.因为它只是一个工具,我们宁可把更多的精力放在C++语言和软件设计上.我们习惯于这样一种"模式":建立一个项目,然后写代码,然后编译,反反复复调试.但是,所谓:"公欲善其事,必先利其器".如果我们精于VC开发环境,我们是不是能够做得更加游刃有余呢? VC的处理流程,大致分