菜单栏

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了菜单栏相关的知识,希望对你有一定的参考价值。

1、菜单相关问题

  Win32--HMENU

  MFC--CMenu类对象

2、相关类

  CMenu - 封装了关于菜单的各种操作,还封装了一个非常重要的成员

    m_hMenu(菜单句柄)

3、菜单项被点击的处理 WM_COMMAND 消息

  ON_COMMAND

4、程序的类对菜单命令的响应顺序

  顺序依次是:视图类->文档类->框架类->应用程序类

  菜单命令消息路由的过程:点击某个菜单项,框架类最先接收到这个命令消息,并交给视图类,视图类查找自身是否对此消息进行了响应,如果响应了,就用相应的响应函数对消息进行处理,路由过程结束,如果没有响应,就交给文档类;文档类同样查找自身是否对此消息进行了响应,如果响应了,就用相应的响应函数对消息进行处理,路由过程结束,如果也没有响应,就交还给视图类,视图类又交还给框架类;这时,框架类才查看自身是否对此消息进行了响应,如果也没有响应就把消息交给最后的应用程序类来进行处理

5、菜单的使用

  5.1添加菜单资源

  5.2设置菜单栏

    在框架类窗口CFrameWnd的消息响应函数OnCreate中设置菜单栏的装载和移除

    BOOL SetMenu(CMenu* pMenu);

    1)装载菜单栏

      CMenu menu;

      menu.LoadMenu(菜单资源ID);  -加载菜单,并将对象和句柄进行绑定

      SetMenu(&menu);

      menu.Detach();

    2)移除菜单栏

      SetMenu(NULL);

  5.3菜单捕获

    1)获取程序的菜单栏:CMenu* GetMenu() const;

    2)获取顶层菜单项:CMenu* GetSubMenu(int nPos) const;

      如:GetSubMenu(0)

  5.4设置菜单项的状态

    ON_WM_INITMENUPOPUP

    标记菜单项: ::CheckMenuItem / CMenu::CheckMenuItem

      UINT CheckMenuItem(UINT nIDCheckItem,UINT nCheck);

        nIDCheckItem:指定需要处理的下拉菜单项,值可为位置索引号(如:0)或者菜单项ID号(如:(UINT)ID_FILE_NEW)

        nCheck:设置菜单项 | 如何定位该菜单项,

          包括:MF_CHECKED/MF_UNCHECKED | MF_BYPOSITION/MF_BYCOMMAND

      例:GetMenu()->GetSubMenu(0)->CheckMenuItem(0,MF_CHECKED|MF_BYPOSITION);

      或者:GetMenu()->GetSubMenu(0)->CheckMenuItem(ID_FILE_NEW,MF_CHECKED|MF_BYCOMMAND);

    默认菜单项: ::SetDefaultItem / CMenu::SetDefaultItem

      BOOL SetDefaultItem(UINT uItem,BOOL fByPos=FALSE);

        uItem:指定需要处理的下拉菜单项,值可为位置索引号(如为-1则表明没有默认菜单项)或者菜单项ID号(如:(UINT)ID_FILE_NEW)

        fByPos:是BOOL类型,若为FALSE,则第一个参数须为菜单项ID号,否则为位置索引号

      例:GetMenu()->GetSubMenu(0)->SetDefaultItem(1,TRUE);

    图形标记菜单: ::SetMenuItemBitmaps / CMenu::SetMenuItemBitmaps

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

        nPosition:指定需要处理的下拉菜单项,值可为位置索引号(如为-1则表明没有默认菜单项)或者菜单项ID号(如:(UINT)ID_FILE_NEW)

        nFlags:MF_BYPOSITION/MF_BYCOMMAND

        pBmpUnchecked:指定当取消菜单项选中状态时的位图

        pBmpChecked:指定选中菜单项时显示的位图

      例:m_bitmap.LoadBitmap(IDB_BITMAP1);

        GetMenu()->GetSubMenu(0)->SetMenuItemBitmaps(0,MF_BYPOSITION,&m_bitmap,&m_bitmap);

        图形标记的大小应为:16x16

    禁用菜单项: ::EnableMenuItem / CMenu::EnableMenuItem

      UINT EnableMenuItem(UINT nIDEnableItem,UINT nEnable);

        nIDEnableItem:指定需要处理的下拉菜单项,值可为位置索引号(如为-1则表明没有默认菜单项)或者菜单项ID号(如:(UINT)ID_FILE_NEW)

        nEnable:MF_DISABLED/MF_ENABLED/MF_GRAYED | MF_BYPOSITION/MF_BYCOMMAND

      注意:若要更改MFC自动创建的菜单项的状态,须修在程序框架窗口类的构造函数中添加:m_bAutoMenuEnable=FALSE;

      例:GetMenu()->GetSubMenu(0)->EnableMenuItem(2,MF_DISABLED|MF_GRAYED|MF_BYPOSITION);

  5.5MFC默认创建的菜单项状态维护

    利用MFC编程时,对于自动创建好的菜单项,可利用MFC类向导的UPDATE_COMMAND_UI消息来改变菜单项状态(只能应用于下拉菜单项),仅需对相应的菜单项的ID生成消息响应函数;

    技术分享

    在UPDATE_COMMAND_UI消息的响应函数中可调用CCmdUI的相应函数如:Enable/SetCheck/SetText,分别实现使菜单项可用或禁用/设置标记菜单/设置菜单项的文本的功能 

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

     工具栏上的各工具按钮和下拉菜单项的ID标识是相同的,改变菜单项的状态工具栏上相应的工具按钮状态也会改变;所以,如果要把工具栏的一个工具按钮与菜单项中的某个菜单项相关联,只要将它们的ID设为同一个就可以了;

    技术分享

    技术分享   

void CMainFrame::OnUpdateFileNew(CCmdUI* pCmdUI) 
{
    // TODO: Add your command update UI handler code here
    pCmdUI->Enable(FALSE);

}

    技术分享

  5.6上下文菜单(右键菜单)

    ON_WM_CONTEXTMENU

    CMenu::TrackPopupMenu / ::TrackPopupMenu -显示弹出式菜单

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

      nFlags:指定菜单在屏幕上显示的位置

      x,y:菜单显示位置处的坐标,这里的坐标是屏幕坐标

      pWnd:指定拥有菜单的窗口对象

    CMenu::GetSubMenu / ::GetSubMenu -获取某个顶层菜单项的下拉菜单

    

    方法一:利用VC提供的组件来创建

      1)VC菜单栏->工程->添加到工程->Components and Controls...

      2)在对话框中双击Visual C++ Components目录

      3)选中“Pop-up Menu”组件,单击<Insert>,确认后就可见到添加右键菜单组件设置对话框

      4)Add pop-up menu to:添加右键菜单到哪个类;Menu resource ID:右键菜单的资源ID;

      5)返回到Visual C++ Components目录下,点击<Close>按钮,完成组件的添加

      在资源窗口的Menu下多了右键菜单的资源;在第4步所选类下增加了函数OnContextMenu,此函数即为右键菜单的调用函数;

    方法二:手动创建

      1)添加菜单资源

        在显示右键菜单时顶层菜单项是不显示的,可以设置任意文本

      2)给CMenuView类添加WM_RBUTTONDOWN消息响应函数;

        技术分享

      3)定义一个CMenu对象,加载菜单项资源,对于右键菜单来说只有一个顶层菜单项,索引位置为0,调用ClientToScreen函数将客户区的坐标转换为屏幕坐标,调用TrackPopupMenu函数显示右键菜单;        

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);
    
    CView::OnRButtonDown(nFlags, point);
}

      4)利用MFC类向导为右键菜单项的各选项添加消息响应函数

        技术分享

        技术分享

  5.7对菜单进行动态操作

    1)创建菜单项

      1--在框架类中创建菜单项

        可在其OnCreate函数中利用:CreateMenu() / CreatePopupMenu()       

int CMainFrame::OnCreate(LPCREATESTRUCT lpCreateStruct)
{
    ......
    CMenu menu;
    menu.CreateMenu();
    GetMenu()->AppendMenu(......);
    menu.Detach();

    return 0;
}

      2--在视图类等其它类的消息响应函数中创建菜单项,须先在该类中添加成员变量:CMenu m_menu

        技术分享        

int CTestView::OnChar(UINT nChar,UINT nRepCnt,UINT nFlags)
{
    ......
    m_menu.CreatePopupMenu();
    GetParent()->GetMenu()->AppendMenu(......);
    GetParent()->DrawMenuBar(); //操作完成后须重绘菜单栏

    return 0;
}

    2)追加菜单项

      利用AppendMenu函数把一个新的菜单项追加到已有菜单项的末尾

      BOOL AppendMenu(UINT nFlags,UINT_PTR nIDNewItem=0,LPCTSTR lpszNewItem=NULL);

      或:BOOL AppendMenu( UINT nFlags, UINT nIDNewItem, const CBitmap* pBmp );

        nFlags:

          MF_POPUP/MF_STRING/MF_SEPARATOR

          MF_CHECKED/MF_UNCHECKED/MF_ENABLED/MF_DISABLED/MF_GRAYED

          MF_OWNERDRAW/MF_MENUBREAK/MF_MENUBARBREAK

        nIDNewItem:如果第一个参数为MF_POPUP,则nIDNewItem就是m_hMenu;否则就为所追加的菜单项的ID;为MF_SEPARATOR时直接忽略

        lpszNewItem:如果第一个参数为MF_STRING,则为指向要添加的菜单项的文本的指针;第一个参数为MF_OWNERDRAW,则为指向要添加的菜单项的附加数据的指针;其它则直接忽略;        

int CMainFrame::OnCreate(LPCREATESTRUCT lpCreateStruct)
{
    ......
    CMenu menu;
    menu.CreateMenu();
    GetMenu()->AppendMenu(MF_POPUP,(UINT)menu.m_hMenu,"Test");
    menu.Detach();

    return 0;
}

    3)插入菜单项

      利用InsertMenu函数在已有菜单项之前插入一个新的菜单项;

      BOOL InsertMenu( UINT nPosition, UINT nFlags, UINT nIDNewItem = 0, LPCTSTR lpszNewItem = NULL );

      或:BOOL InsertMenu( UINT nPosition, UINT nFlags, UINT nIDNewItem, const CBitmap* pBmp );

        nPosition:指定新菜单项的插入位置;取决于第二个参数nFlags为MF_BYCOMMAND还是WM_BYPOSITION;

        nFlags:和AppendMenu中的参数一样 | MF_BYCOMMAND/MF_BYPOSITION

        nIDNewItem、lpszNewItem:均与AppendMenu中的参数一样      

int CMainFrame::OnCreate(LPCREATESTRUCT lpCreateStruct)
{
    ......
    CMenu menu;
    menu.CreateMenu();
    //在菜单栏的第二个位置处插入新的顶层菜单项
    GetMenu()->InsertMenu(1,MF_POPUP|MF_BYPOSITION,(UINT)menu.m_hMenu,"Test");
    //在新插入的顶层菜单项下添加下拉菜单项
    menu.AppendMenu(MF_STRING,(UINT)IDR_MENU1,"Hello");
    menu.AppendMenu(MF_STRING,(UINT)IDR_MENU2,"VC++");
    menu.AppendMenu(MF_STRING,(UINT)IDR_MENU3,"MFC");
    menu.Detach();
    //在菜单栏首个顶层菜单项下追加下拉菜单项
    GetMenu()->GetSubMenu(0)->AppendMenu(MF_STRING,(UINT)IDR_MENU1,"Welcom");
    //在菜单栏首个顶层菜单项下插入下拉菜单项
    GetMenu()->GetSubMenu(0)->InsertMenu(0,MF_BYPOSITION|MF_STRING,(UINT)IDR_MENU5,"Autumn");

    return 0;
}

    4)删除菜单项

      BOOL DeleteMenu(UINT nPosition,UINT nFlags);      

int CMainFrame::OnCreate(LPCREATESTRUCT lpCreateStruct)
{
    ......
    //删除顶层菜单项
    GetMenu()->DeleteMenu(1,MF_BYPOSITION);
    //删除下拉菜单项
    GetMenu()->GetSubMenu(0)->DeleteMenu(0,MF_BYPOSITION);

    return 0;
}

    5)动态添加的菜单项的响应命令

      动态添加的菜单项未在资源窗口中添加相应的菜单项资源,故没有相应的菜单项ID标识;

      1--首先为动态添加的菜单项创建菜单资源ID,在文件窗口中打开Header Files目录,在Resource.h文件中定义资源ID

        例:#define IDM_HELLO      111

      2--动态追加菜单项AppendMenu函数和动态插入菜单项InsertMenu函数的UINT nIDNewItem参数即为菜单项资源ID(IDM_HELLO)

      3--在菜单项命令所在的类(框架类)的头文件中添加命令响应函数的原型      

class CMainFrame : public CFrameWnd
{
    ......
// Generated message map functions
protected:
    //{{AFX_MSG(CMainFrame)
    afx_msg int OnCreate(LPCREATESTRUCT lpCreateStruct);
        // NOTE - the ClassWizard will add and remove member functions here.
        //    DO NOT EDIT what you see in these blocks of generated code!
    //}}AFX_MSG

    afx_msg void OnHello();

    DECLARE_MESSAGE_MAP()
};

      4--在菜单项命令所在的类(框架类)的源文件中的映射表添加消息映射     

BEGIN_MESSAGE_MAP(CMainFrame, CFrameWnd)
    //{{AFX_MSG_MAP(CMainFrame)
        // NOTE - the ClassWizard will add and remove mapping macros here.
        //    DO NOT EDIT what you see in these blocks of generated code !
    ON_WM_CREATE()
    //}}AFX_MSG_MAP

    ON_COMMAND(IDM_HELLO,OnHello)  //注意这里结尾没有分号

END_MESSAGE_MAP()

      5--在菜单项命令所在的类(框架类)的源文件中添加消息响应函数的定义      

void CMainFrame::OnHello()
{
    MessageBox("Hello");
}

 

以上是关于菜单栏的主要内容,如果未能解决你的问题,请参考以下文章

如何将片段目标绑定到底部导航栏中的菜单项?

sublimetext3中保存代码片段

Android 如何从 Fragment 编辑操作栏菜单

如何从活动意图到特定片段

android:来自片段的菜单项单击事件

导航菜单和在android中的选择性片段上添加按钮