• 菜单基本操作


    前言


    本主要介绍菜单的基本使用,在MFC中用于指定菜单项位置有两种方式,它们是MF_BYCOMMAND和MF_BYPOSITION,在菜单操作中经常用到,具体含义如下:

    MF_BYCOMMAND 是指将相关参数解释为菜单项ID(缺省值)
    MF_BYPOSITION    是指将相关参数解释为零基偏移的菜单项,需要特别注意,菜单中的分隔符也占据一个位置


    如图1是一个MFC窗口,其中文件、编辑、视图所在的位置是菜单栏,其中“文件(F)”、“编辑(E)”都是子菜单,“新建(N)”,“保存(S)”等是菜单项。菜单项可以通过菜单项的标识ID进行访问,而子菜单只能通过索引号进行访问


                                                   图1 MFC窗口

    在CWnd类中,MFC提供了5个关于菜单的接口,同时MFC还为我们提供了CMenu类,该类是Windows HMENU的封装类。它提供了成员函数以用于创建、追踪、更新及销毁菜单,在文章末尾给出它们成员函数,这里主要介绍CWnd类的5个接口和CMenu类中基本菜单操作接口。


    CWnd类菜单


    DrawMenu函数用于重画菜单条。如果在Windows创建窗口以后菜单条发生了改变,则应调用这个函数以画出改变了的菜单条,声明如下:

    void DrawMenuBar( );

    GetMenu函数用于获得主窗口菜单栏指针,其函数声明如下:

    CMenu* GetMenu( ) const;

    GetSystemMenu用于应用程序访问控制菜单,用于拷贝和修改,其函数声明如下:

    CMenu* GetSystemMenu( BOOL bRevert ) const;

    HiliteMenuItem用于加亮显示一个顶层(菜单条)菜单项或清除其加亮显示状态,其函数声明如下:

    BOOL HiliteMenuItem( CMenu* pMenu, UINT nIDHiliteItem, UINT nHilite );

    SetMenu将当前菜单设为指定的菜单。它使窗口被重画以反映菜单的变化,其函数声明如下:

    BOOL SetMenu( CMenu* pMenu );


    CMenu类菜单操作


    我们可以通过GetMenu获得菜单栏的指针,而子菜单的指针是通过CMenu类中的GetSubMenu来完成的,其函数声明如下:

    CMenu* GetSubMenu( int nPos ) const;

    由于程序的主菜单属于框架窗口,所以需要在框架窗口创建完成之后,再去访问菜单对象,我们可以在框架类的OnCreate函数return之前添加相应的代码,如果在CMainFrame类中没有OnCreate响应函数,需要我们手动添加该函数。


    标记菜单


    在视图子菜单下面有“工具栏(T)”和"状态栏(S)"两个菜单项,在它们前面都有一个对号(√),我们称这种类型的菜单为“标记菜单”,如图2所示。


                                    图2 标记菜单

    为了实现这样的标记菜单,我们可以调用CMenu中的CheckItem函数来完成这样的效果,其函数声明如下:

    UINT CheckMenuItem( UINT nIDCheckItem, UINT nCheck );
    

    现在我们将“文件(F)”下的“打开(O)”菜单项设置为标记菜单,实现代码如下:

    int CMainFrame::OnCreate(LPCREATESTRUCT lpCreateStruct)
    {
        ...
        //标记菜单
        GetMenu()->GetSubMenu(0)->CheckMenuItem(ID_FILE_OPEN, MF_BYCOMMAND | MF_CHECKED);
        return 0;
    }
    
    

    运行效果:

    默认菜单

    在一些应用程序中的子菜单下有一个菜单项,它是以粗体形式出现的,以这种形式显示的就是该子菜单的默认菜单,我们可以利用SetDefaultItem函数来完成这个设置,其函数声明如下:

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

    实现代码如下:

    int CMainFrame::OnCreate(LPCREATESTRUCT lpCreateStruct)
    {
        ...
        //默认菜单
        GetMenu()->GetSubMenu(0)->SetDefaultItem(ID_FILE_NEW, FALSE);
        return 0;
    }

    
    运行效果:
    

    图形标记菜单

    为了实现图形标记菜单项的效果,可以利用SetMenuItemBitmaps函数来显示,这个函数的作用是将制定的位图和菜单项关联起来,其函数声明如下:

    BOOL SetMenuItemBitmaps( UINT nPosition, UINT nFlags, const CBitmap* pBmpUnchecked, const CBitmap* pBmpChecked );
    在图形标记菜单中,显示的位图尺寸有固定的大小,其高度和宽度都是13*13

    代码实现如下:

    int CMainFrame::OnCreate(LPCREATESTRUCT lpCreateStruct)
    {
        ...
        //图形标记菜单
        m_BmpItem.LoadBitmap(IDB_BITMAP1);
        GetMenu()->GetSubMenu(0)->SetMenuItemBitmaps(2, MF_BYPOSITION, &m_BmpItem, &m_BmpItem);
        return 0;
    }
    运行效果:



    禁用菜单


    为了达到屏蔽某些菜单功能,我们可以使用EnableMenuItem函数来实现,该函数的功能是设置菜单状态:能够使用、禁用或变灰显示,其函数如下:

    UINT EnableMenuItem( UINT nIDEnableItem, UINT nEnable );
    为了将EnalbeMenuItem函数正常生效,需要在MainFrame构造函数中将m_bAutoEnableMenus设置为False,此时MFC菜单项的显示状态不会自动更新,需要我们自己维护菜单显示状态

    我们将m_bAutoEnableMenu设置为False后,那些没有设置功能的菜单项也都会显示为非灰色,造成误解,为了将某些功能禁用需要调用EnableMenuItem函数,具体代码:

    int CMainFrame::OnCreate(LPCREATESTRUCT lpCreateStruct)
    {
        ...
        //禁用编辑下的所有菜单项功能
        CMenu *SubEditMenu = GetMenu()->GetSubMenu(1);
        SubEditMenu->EnableMenuItem(0, MF_BYPOSITION | MF_DISABLED | MF_GRAYED);
        SubEditMenu->EnableMenuItem(2, MF_BYPOSITION | MF_DISABLED | MF_GRAYED);
        SubEditMenu->EnableMenuItem(3, MF_BYPOSITION | MF_DISABLED | MF_GRAYED);
        SubEditMenu->EnableMenuItem(4, MF_BYPOSITION | MF_DISABLED | MF_GRAYED);
        return 0;
    }
    运行效果:



    移除和装载菜单


    在程序中,如果希望移除一个菜单的话或同时加载一个新的菜单可以利用Cwnd类提供的setMenu函数来实现。移除和装载一个菜单代码实现如下:

    int CMainFrame::OnCreate(LPCREATESTRUCT lpCreateStruct)
    {
        ...
        //默认的菜单栏从窗口中移除
        SetMenu(NULL);
    
        //设置新的菜单栏
        CMenu menu;
        menu.LoadMenu(IDR_MENU_TEST);//自定义的菜单栏
        //将自定义菜单栏绑定到窗口
        SetMenu(&menu);
    
        //将menu对象中的m_hMenu和菜单栏资源分离,
        //避免menu对象析构时,菜单栏资源也被析构
        menu.Detach(); 
        /*
        HMENU CMenu::Detach()
        {
        HMENU h = m_hMenu;
        m_hMenu = NULL;
    
        return h;
        }
        */
        return 0;
    }
    运行效果:



    快捷菜单


    如果我们想要提供一个右键快捷菜单功能,我们可以添加ON_WM_CONTEXTMENU或者ON_WM_RBUTTONDOWN消息响应函数,在消息响应函数中调用TrackPopupMenu函数来完成,其函数声明如下:

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

    具体代码如下:

    方式一:

    void CCMenuView::OnContextMenu(CWnd* /*pWnd*/, CPoint point)
    {
        // TODO: 在此处添加消息处理程序代码
        CMenu menu;
        VERIFY(menu.LoadMenu(IDR_MENU_RBUTTON));
        CMenu* pPopup = menu.GetSubMenu(0);
    
        pPopup->TrackPopupMenu(TPM_LEFTALIGN | TPM_RIGHTBUTTON, point.x,
                                point.y, this);
    }

    方式二:

    void CCMenuView::OnRButtonDown(UINT nFlags, CPoint point)
    {
        // TODO: 在此添加消息处理程序代码和/或调用默认值
    
        //该消息响应函数需要将转换鼠标点击坐标
        ClientToScreen(&point);
    
        CMenu menu;
        VERIFY(menu.LoadMenu(IDR_MENU_RBUTTON));
        CMenu* pPopup = menu.GetSubMenu(0);
        pPopup->TrackPopupMenu(TPM_LEFTALIGN | TPM_RIGHTBUTTON, point.x,
            point.y, this);
    
        CView::OnRButtonDown(nFlags, point);
    }
    运行效果:



    CMenu类的成员函数


    构造函数

    CMenu 构造一个CMenu对象

    初始化
    Attach 附加一个Windows菜单句柄给CMenu对象
    Detach 从CMenu对象中分离Windows菜单的句柄,并返回该句柄
    FromHandle 返回一个指向给定Windows菜单句柄的CMenu对象的指针
    GetSafeHmenu 返回由CMenu对象包含的m_hMenu值
    DeleteTempMap 删除由FromHandle成员函数创建的所有临时CMenu对象
    CreateMenu 创建一个空菜单,并将其附加给CMenu对象
    CreatePopupMenu 创建一个空的弹出菜单,并将其附加给CMenu对象
    LoadMenu 从可执行文件中装载菜单资源,并将其附加给CMenu对象
    LoadMenuIndirect 从内存的菜单模板中装载菜单,并将其附加给CMenu对象
    DestroyMenu 销毁附加给CMenu对象的菜单,并释放菜单占用的内存

    菜单操作
    DeleteMenu 从菜单中删除指定的项。如果菜单项与弹出菜单相关联,那么将销毁弹出菜单的句柄,并释放它占用的内存
    TrackPopupMenu 在指定的位置显示浮动菜单,并跟踪弹出菜单的选择项

    菜单项操作
    AppendMenu 在该菜单末尾添加新的菜单项
    CheckMenuItem 在弹出菜单的菜单项中放置或删除检测标记
    CheckMenuRadioItem 将单选钮放置在菜单项之前,或从组中所有的其它菜单项中删除单选钮
    SetDefaultItem 为指定的菜单设置缺省的菜单项
    GetDefaultItem 获取指定的菜单缺省的菜单项
    EnableMenuItem 使菜单项有效、无效或变灰
    GetMenuItemCount 决定弹出菜单或顶层菜单的项数
    GetMenuItemID 获取位于指定位置菜单项的菜单项标识
    GetMenuState 返回指定菜单项的状态或弹出菜单的项数
    GetMenuString 获取指定菜单项的标签
    GetMenuItemInfo 获取有关菜单项的信息
    GetSubMenu 获取指向弹出菜单的指针
    InsertMenu 在指定位置插入新菜单项,并顺次下移其它菜单项
    ModifyMenu 改变指定位置的已存在的菜单项
    RemoveMenu 从指定的菜单中删除与弹出菜单相关联     的菜单项
    SetMenuItemBitmaps 将指定检测标记的位图与菜单项关联
    GetMenuCountextHelpID 获取与菜单关联的帮助文本的ID号
    SetMenuCountextHelpID 设置与菜单关联的帮助文本的ID号 


  • 相关阅读:
    osharp3引入事务后操作结果类别的调整
    Code First 迁移
    表达式拼接Expression<Func<IEntityMapper, bool>> predicate
    ASP.NET中Session的sessionState 4种mode模式
    EF Code First Migrations数据库迁移
    啊里大鱼短信发送API
    asp.net服务器控件的生命周期
    osharp3使用经验:整合DbContextScope 文章 1
    关于MarshalByRefObject的解释
    数据库操作事务IsolationLevel 枚举
  • 原文地址:https://www.cnblogs.com/jinxiang1224/p/8468375.html
Copyright © 2020-2023  润新知