孙鑫VC学习笔记:第六讲 菜单

来源:互联网 发布:淘宝怎样才能货到付款 编辑:程序博客网 时间:2024/05/22 01:28
 

CMenuApp 并不是从CWnd派生出来的,所以不能使用MessageBox函数。
           但可以使用全局的MessageBox函数:AfxMessageBox函数
           int AfxMessageBox(LPCTSTR lpszText,UINT nType,UINT nIDHelp);
          
           对菜单项Test响应的顺序:           View-Doc-MainFrame-App
          
                          消息的分类
          
标准消息      除WM_COMMAND之外,所有以WM_开头的消息。从CWnd派生的类,都可以接收到这类消息。

命令消息      来自菜单、加速键或工具栏按钮的消息。这类消息都以WM_COMMAND呈现。
              在MFC中,通过菜单项的标识(ID)来区分不同的命令消息;
              在SDK中,通过消息的wParam参数识别。从CCmdTarget派生的类,都可以接收到这类消息。
            
通告消息      由控件产生的消息,例如,按钮的单击,列表框的选择等均产生此类消息,
              为的是向其父窗口(通常是对话框)通知事件的发生。
              这类消息也是以WM_COMMAND形式呈现。从CCmdTarget派生的类,都可以接收到这类消息。

  CWnd是由CCmdTarget派生
 
 
CWnd::GetMenu
 CMenu* GetMenu()const;
 
  CMenu封装了一些和菜单有关的操作,封装了windows的HMENU(菜单句柄)
 
  CMenu::GetSubMenu
   CMenu* GetSubMenu( int nPos) const; //获取子菜单
   
  CMenu::CheckMenuItem
   UINT CheckMenuItem( UINT nIDCheckItem, UINT nCheck);// Return the previous state of the item   
   
  CMenu::SetDefaultIte
   //BOOL SetDefaultItem( UINT uItem, BOOL fByPos=FALSE) //设置缺省的菜单项
    指定的缺省菜单项将会被加黑显示
   
 CAUTION! 一个子菜单中,只能有一个缺省菜单项
 
 CMenu::SetMenuItemBitmaps
  //BOOL SetMenuItemBitmaps( UINT nPosition, UINT nFlags,
                             const CBitmaps* pBmpUnchecked, const CBitmaps* pBmpChecked)
 创建图形标记菜单
 获取图形标记菜单位图的大小:
    int GetSystemMetrics( int nIndex)
    nIndex: //system metric or configuration setting
     SM_CXMENUCHECK  //缺省的菜单标记位图的高度
      SM_CYMENUCHECK  //缺省的菜单标记位图的宽度
     
     
CString str;

str.Format("x=%d, y=%d",GetSystemMetrics(SM_CXMENUCHECK),
                        GetSystemMetrics(SM_CYMENUCHECK));
MessageBox(str);

//改变菜单项的状态
CMenu::EnableMenuItem
 UINT EnableMenuItem( UINT nIDEnableItem, UINT nEnable );
 
 CAUTION!  只有在CMainFrame的构造函数中将变量 m_bAutoMenuEnable=FALSE时,
           EnableMenuItem函数才会起作用
           m_bAutoMenuEnable=FALSE时MFC就不会使用他的命令更新机制去判断哪个菜单项能使用
           哪个菜单项不能使用,此时这些操作都要由我们自己去完成

如何将整个菜单取消:
  CWnd::SetMenu
   //BOOL SetMenu( CMenu* pMenu);
   SetMenu( NULL);  //移走当前菜单
   
重新加载菜单:
  CMenu menu; // 不能是局部对象
  menu.LoadMenu( IDM_MAINFRAME /×菜单ID*/)//动态的更换菜单
  SetMenu(&menu);
  menu.Detach();//如果menu是局部对象,一定要调用Detach()函数,它将菜单的句柄和我们的C++对象断开,
                  这样当局部对象CMenu析构时,不会销毁我们的菜单
 
   
MFC对菜单项采用的命令更新机制:01:18:00
 
                              命令更新
 
  菜单项状态的维护是依赖于CN_UPDATE_COMMAND_UI消息,谁捕获CN_UPDATE_COMMAND_UI消息,
 MFC就在其中创建一个CCmdUI对象。我们可以通过手工或利用ClassWizard在消息映射中添加
 ON_UPDATE_COMMAND_UI宏来捕获CN_UPDATE_COMMAND_UI消息。
 
  在后台所做的工作是:操作系统发出WM_INITMENUPOPUP消息,然后由MFC的基类如CFrameWnd接管。
  它创建一个CCmdUI对象,并与第一个菜单项相关联,调用对象的一个成员函数DoUpdate()。
  这个函数发出CN_UPDATE_COMMAND_UI消息,这条消息带有指向CCmdUI对象的指针。同一个
  CCmdUI对象就设置为与第二个菜单项相关联,这样顺序进行,直到完成所有菜单项。
 
  更新命令UI处理程序仅应用于弹出式菜单项上的项目,不能应用于永久显示的顶级菜单项目。

void CMainFrame::OnUpdateEditCut( CCmdUI* pCmdUI)
 {
  pCmdUI->Enable();//Enable()函数的缺省参数为 BOOL类型TRUE  
 }
 
 工具栏上的图标,和它所对应的菜单项的ID号是一样的。所以当对菜单项DISABLE或者ENABLE时能够相应
 的在工具栏上显现出来。
 CAYTION!:如果在改变菜单项状态的过程中是用的菜单项ID号,则菜单项状态的改变能在工具栏上相应的
         图标上显现出来,但如果使用的是菜单项的位置索引,则相应的状态不会在工具栏上显现出来。
         这是因为工具栏上的图标和相应菜单项具有相同的ID号,但位置索引是不相同的。
        
实现右键弹出菜单的功能:
   Project->Add To Project->Components and Controls->Visual C++ Components->Pop-up Menu
  
注意:应该把菜单加入CMenuView类

此时,会在CMenuView类中加入一个函数OnContextMenu( CWnd* , CPoint)
 //CWnd::OnContextMenu
 //afx_msg void OnContextMenu( CWnd* pWnd,CPoint pos)
 //Called by framework when the user has clicked the right mouse button(right clicked)
 //in the window.You can process(处理)this message by displaying a context menu using the
 //TrackPopupMenu(用来显示弹出菜单)
 CMenu:: TrackPopupMenu
  //BOOL TrackPopupMenu( UINT nFlags,  //弹出菜单相对于x的位置
                         int x, int y, //鼠标点击的位置坐标,注意这个位置坐标是相对于屏幕坐标
                                       //而不是客户区坐标,使用是需要进行坐标转换
                         CWnd* pWnd,   //菜单的拥有者
                         LPCRECT lpRect=NULL //指定一个矩形,当鼠标在矩形外点击时,菜单消失
                                             //在矩形内点击时,弹出菜单不消失
                       );
                      
                      
  坐标转换:
  CWnd::ClientToScreen
    void ClientToScreen( LPPOINT lpPoint) const;
    void ClientToScreen( LPRECT lpRect) const;
   
 为弹出菜单的“显示”菜单项,在CMenuView和CMainFrame类中分别加入命令捕获OnShow函数
 
 选中“显示”项,发现只有CMenuView类对菜单命令进行捕获,原因是用TrackPopupMenu显示弹出
 菜单时,指定了弹出菜单的拥有者窗口指针
 即使将指针设置为父窗口指针,子窗口依然最先响应菜单命令,只有当子窗口不响应时,才交由父窗口响应
 
 通过代码来动态添加菜单
 CMenu::AppendMenu
  //BOOL AppendMenu( UINT nFlags, UINT nIDNewItem=0, LPCTSTR lpszNewItem=NULL);
  //BOOL AppendMenu( UINT nFlags, UINT nIDNewItem, const CBitmap* pBmp);
  //可以将一个菜单或者一个菜单项添加到现有菜单的末尾
  //nFlags: MF_STRING MF_POPUP MF_SEPARATOR
  //nIDNewItem:当nFlags=MF_POPUP,则nIDNewItem为POPUP菜单的句柄
               //当nFlags=MF_SEPARATOR,则nIDNewItem被Ignored
              
 CMenu::CreatePopupMenu
  //Creates an empty pop-up menu and attaches it to a CMenu object
  //BOOL CreatePopupMenu()
  
 插入菜单
  CMenu::InsertMenu
   //BOOL InsertMenu( UINT nPosition, UINT nFlags, UINT nIDNewItem=0,LPCTSTR lpszNewItem);
    //BOOL InsertMenu( UINT nPosition, UINT nFlags, UINT nIDNewItem,const CBitmap* pBmp);
    //nPosition的取值由nFlags来确定,如果nFlags=MF_BYPOSITION,则nPosition为位置所以号
                                   //如果nFlags=MF_BYCOMMAND,则nPosition为菜单项ID号
    //nIDNewItem:当nFlags=MF_POPUP,则nIDNewItem为POPUP菜单的句柄
               //当nFlags=MF_SEPARATOR,则nIDNewItem被Ignored
删除子菜单
  CMenu::DeleteMenu()
   //BOOL DeleteMenu( UINT nPosition, UINT Flags); //删除一个指定的菜单项或弹出菜单
   
对动态创建的菜单项进行命令响应
    头文件Resource.h定义了资源的ID
    做一个菜单命令的命令响应函数,它的添加和消息响应函数时一样的,一共有三个步骤:
    step1:首先在头文件中做命令响应函数的原型
               //MainFrm.h
               //protected:
               //afx_msg void OnHello();
    step2: 消息映射                       //使用教程中的方法时,消息映射一定要放到注释宏的外面
          //MainFrm.cpp  
          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/*ID号*/,OnHello/*命令响应函数*/)   //注意!不要加任何的标点符号
      END_MESSAGE_MAP()
    step3:命令响应函数的实现
             //MainFrm.cpp
             void CMainFrame::OnHello()
             {
          MessageBox("Hello!");
        }

编写电话本程序

注:菜单栏是属于框架窗口的,在view类中调用GetMenu()是无法获得指向菜单的指针的,因为view窗口根本
    没有菜单
   
对菜单栏进行重绘
    CWnd::DrawMenuBar
     void DrawMenuBar()
     //Redraw the menu bar .If a menu bar is changed after windows has created the window,
     //cal the function to draw the changed menu bar.
     利用父窗口(框架窗口)调用DrawMenuBar

对窗口进行重绘
    CWnd::Invalidate
    //void Invalidate( BOOL bErase=TRUE)
   
CString的查找功能
    CString::Find
      int Find( TCHAR ch)const;
      int Find( LPCTSTR lpszSub)const;
      int Find( TCHAR ch, int nStart)const;
      int Find( LPCTSTR pstr, int nStart)const;
    Return Value
      返回基于0的第一个匹配的字符(串)索引,如果找不到,返回-1

存储字符串集合类 CStringArray     
     
CWnd::OnCommand
 //virtual BOOL OnCommand( WPARAM wParam, LPARAM lParam) 虚函数
 //The framework calls this member function when the user selects an item from a menu,when a
 //child control sends a notification message(通告消息),or when an accelerator keystroke is
 //translated
 //OnCommand 处理消息映射
 
如何得到框架窗口下的视图窗口的指针:
  CFrameWnd::GetActiveView
   CView* GetActiveView() const;
 Return Value
   A point to the current CView.If there is no current view, returns NULL.
   //获取当前视类的指针  

 
原创粉丝点击