孙鑫vc++ 第六课 笔记 菜单的工作原理及编写应用

本文介绍了VC++中菜单的工作原理,包括命令消息的路由、菜单响应的类层次结构、菜单状态的更新机制。讲解了如何设置和操作菜单,如设置默认项、添加复选标记、启用禁用菜单项、图形菜单以及右键菜单的实现。同时,还讨论了动态添加和删除菜单项,以及菜单项命令的响应和更新。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

菜单的工作原理及编写应用

今天赶了2场酒,累死了,但还是坚持看完了第6课,写了点笔记,大家鼓励鼓励嘛,不要看看就走了

1、菜单如果选择了pop-up属性,是不能响应命令的
   菜单idm_test--框假类cmainframe--消息command--响应函数OnTest()
                       |
     其实可以为不同的类定制这样的消息响应,响应顺序为:view-doc-mainframe-app

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

   CWnd : CCmdTarget : CObject
   从CWnd派生的类,都可以接收到标准消息。
   从CCmdTarget派生的类,都可以接收到命令消息。
   于是从CWnd派生的类既可以接收标准消息,也可以接收命令消息。
   而app类和doc类都是直接从CCmdTarget派生的

   命令消息机制与标准消息类似,只是在.cpp文件中其消息宏有点不一样ON_COMMAND(IDM_TEST,OnTest)

3、命令消息的路由和标准消息不一样
     AfxWndProc              //mfc将窗口过程函数替换为此函数
             |
     AfxCallWndProc          //
         |
  WindowProc               //CWnd类成员函数
      |
   OnWndMsg                 //判断消息类型
         ___________|____________
         |   |
     OnCommand     OnNotify      //命令消息(完成命令消息路由) , 通告消息
         |__________ ___________|
                    |
                OnCmdMsg        

      OnCommand路由过程:mainframe(无判断直接交)->view->doc->view->mainframe->app

4、标记菜单(有钩号)
  
   菜单结构
   3  300  301  302  303  304
   2 
   1
   0
       0    1    2    3    4

5、CWnd::GetMenu
   CMenu* GetMenu() const;  //获取框架上菜单的指针

   CMenu : CObject

   CMenu::GetSubMenu
   CMenu* GetSubMenu(int nPos)const;  //获取子菜单的指针

   CMenu::CheckMenuItem
   UINT CheckMenuItem(UINT nIDCheckItem, UINT nCheck);   //第一个参数的含义由第二个参数决定
                         菜单id        MF_BYCOMMAND      //按id访问
                         菜单索引号    MF_BYPOSITION     //按索引访问

   为某菜单增加复选标记
   GetMenu()->GetSubMenu(0)->CheckMenuItem(0,MF_BYPOSITION | MF_CHECKED);

6、设置缺省菜单项
   CMenu::SetDefaultItem
   BOOL SetDefaultItem(UINT uItem, BOOL fByPos = FALSE); //第一个参数的含义由第二个参数决定
                          菜单id        FALSE      //按id访问
                          菜单索引号    TRUE       //按索引访问

   分隔栏也占一个索引号
   一个子菜单只能有一项缺省菜单项,以后一个定义的缺省定义为准

7、图形菜单
   CMenu::SetMenuItemBitmaps
   BOOL SetMenuItemBitmaps(UINT nPosition, UINT nFlags, const CBitmap* pBmpUnchecked,
                            const CBitmap* pBmpChecked); //第一个参数的含义由第二个参数决定
                                                         //菜单选择图,取消选择图
  
   GetMenu()->GetSubMenu(0)->SetMenuItemBitmaps(0,MF_BYPOSITION,&m_bitmap,&m_bitmap);
   位图大小:13*13
   
8、int GetSystemMetrics(int nIndex);  //按给出的标记获取系统相应的信息

9、菜单变灰
   CMenu::EnableMenuItem
   UINT EnableMenuItem(UINT nIDEnableItem, UINT nEnable); //第一个参数的含义由第二个参数决定

   1 类构造函数中:m_bAutoMenuEnable=FALSE;  //变量无须定义,影响所有菜单
   2 GetMenu()->GetSubMenu(0)->EnableMenuItem(0,MF_BYPOSITION | MF_DISABLED | MF_GRAYED);

10、CWnd::SetMenu
   BOOL SetMenu(CMenu* pMenu);  //参数为菜单指针,NULL,则整个菜单条不见了
 
   SetMenu(NULL);  //菜单不见了
   CMenu menu;    //要设为成员变量,否则出错,或者用Detach()
   menu.LoadMenu(IDR_MAINFRAME_MENU);  //载入菜单资源
   SetMenu(&menu);  //菜单回来了
   menu.Detach();   //后面加的

   SetMenu()设置的是一个新的菜单,必须用Detach()断开菜单句柄和CMenu对象的联系
   Detach()将HMENU这个句柄从CMenu对象中断开,这样,当CMenu对象被析构的时候,菜单不会被销毁,这样就避免了因为用的是局部变量对象而产生的错误

11、菜单项命令更新机制
   菜单项状态的维护是依赖于CN_UPDATE_COMMAND_UI消息,谁捕获CN_UPDATE_COMMAND_UI消息,MFC就在其中创建一个CCmdUI对象。我们可以通过手工或利用ClassWizard在消息映射中添加ON_UPDATE_COMMAND_UI宏来捕获CN_UPDATE_COMMAND_UI消息。
   在后台所做的工作是:当要显示一个菜单的时候,操作系统发出WM_INITMENUPOPUP消息,然后由MFC的基类如CFrameWnd接管。它创建一个CCmdUI对象,并与第一个菜单项相关联,调用CCmdUI对象的一个成员函数DoUpdate()。这个函数发出CN_UPDATE_COMMAND_UI消息,这条消息带有指向CCmdUI对象的指针。同一个CCmdUI对象就设置为与第二个菜单项相关联,这样顺序进行,直到完成所有菜单项。
   更新命令UI处理程序仅应用于弹出式菜单项上的项目,不能应用于永久显示的顶级菜单项目。

   为剪切菜单项添加CN_UPDATE_COMMAND_UI消息响应函数OnUpdateEditCut(CCmdUI* pCmdUI){}
      CCmdUI::SetText
      virtual void SetText(LPCTSTR lpszText);  //改变菜单项的文本

      CCmdUI::Enable
      virtual void Enable(BOOL bOn = TRUE);  //设置菜单可用/不可用,缺省参数为TRUE

   OnUpdateEditCut(CCmdUI* pCmdUI){pCmdUI->Enable();}//剪切菜单项就可用了/波及工具栏响应按钮
   为什么剪切菜单项可用的时候相应工具栏就能用了呢,他们是如何关联的呢
   靠,原来剪切菜单项的id和相应工具栏的id是一模一样的,id_edit_cut
   以后要让工具栏与菜单项相关联,只要将id设为一致的就行了

   pCmdUI->m_nID  保存了与当前CCmdUI对象相关联的菜单项的id
   pCmdUI->m_Index  保存了与当前CCmdUI对象相关联的菜单项的索引值
  
   void CMainFrame::OnUpdateFileNew(CCmdUI* pCmdUI)
   {
      if(ID_FILE_NEW==pCmdUI->m_nID)  //如果改为索引判断,则不能和菜单成功关联,原因是
            pCmdUI->Enable(FALSE);    //工具栏另有索引,so,最好用id
   }
  

12、右键菜单
   工程-增加工程-组件和控件,选择增加一个 pop-up Menu ,选择增加到哪个类中,如view
   1 菜单资源中出现了一个新的菜单
   2 .cpp中增加了一个新的函数OnContextMenu(),里面已经有代码了
      CWnd::OnContextMenu
      afx_msg void OnContextMenu(CWnd* pWnd, CPoint pos); 
      主要在右键按下时被框架调用,随后可以用TrackPopupMenu()显示菜单
      CMenu::TrackPopupMenu
      BOOL TrackPopupMenu(UINT nFlags,int x,int y,CWnd* pWnd,LPCRECT lpRect=NULL);
                      相对鼠标显示位置,鼠标当前坐标,哪个窗口的菜单,响应点击区域
           显示菜单的时候,显示坐标为屏幕坐标,而不是客户区坐标

   手动增加一个
   1 建立菜单资源,设置、记住id
   2 添加右键消息和处理函数
   3 在函数中添加和OnContextMenu()类似的内容,当然也调用TrackPopupMenu()
  
   CWnd::ClientToScreen     //转换客户区坐标为屏幕坐标
   void ClientToScreen(LPPOINT lpPoint)const;
   void ClientToScreen(LPRECT lpRect)const;  //结果输出至参数

   void CMenuView::OnRButtonDown(UINT nFlags, CPoint point)
   {
      ClientToScreen(&point); //转换坐标
      CMenu menu;
      menu.LoadMenu(IDR_MENU1);  //载入资源
      CMenu *pPopop = menu.GetSubMenu(0);  //获取子菜单指针
      pPopop->TrackPopupMenu(IPM_LEFTALIGN | IPM_HIGHIBUTTON,point.x,point.y,this);
     
      CView::OnRButtonDown(nFlags,point); // 这句原来有的
   }  

13、为右键菜单项增加命令响应
   右键菜单资源选择类向导-不建立类-选择COMMAND消息并添加处理函数

14、动态添加菜单
    CMenu::AppendMenu    //添加一个菜单项到现有菜单的末尾
    BOOL AppendMenu(UINT nFlags,UINT nIDNewItem=0,LPCTSTR lpszNewItem=NUll);
    BOOL AppendMenu(UINT nFlags,UINT nIDNewItem,const CBitMap* pBmp);
                    菜单类型,菜单对象索引,菜单的名称

    CMenu::CreatePopupMenu
    BOOL CreatePopupMenu();  //创建一个空的弹出菜单,并把菜单资源和菜单对象相关联起来

    CMenu menu;  //要定义成成员变量,或者用menu.Detach(),否则对象离开函数被析构后产生错误
    menu.CreatePopupMenu();  //创建空菜单
    GetMenu()->AppendMenu(MF_POPUP,(UINT)menu.m_hMenu,"WinSun");  //把菜单添加到现有菜单末尾
    menu.Detach();  //后面加的                 |--->这里用了菜单对象的句柄,然后强制类型转换

15、插入菜单
    CMenu::InsertMenu
    BOOL InsertMenu(UINT nPosition,UINT nFlags,UINT nIDNewItem=0,LPCTSTR lpszNewItem=NULL);
    BOOL InsertMenu(UINT nPosition,UINT nFlags,UINT nIDNewItem,const CBitmap* pBmp);
   
    GetMenu()->InsertMenu(2,MF_BYPUSITION | MF_POPUP,(UINT)menu.m_hMenu,"WinSun");//插入菜单

16、插入菜单项

    CMenu menu;  //要定义成成员变量,或者用menu.Detach(),否则对象离开函数被析构后产生错误
    menu.CreatePopupMenu();  //创建空菜单
    GetMenu()->AppendMenu(MF_POPUP,(UINT)menu.m_hMenu,"WinSun");  //把菜单添加到现有菜单末尾
    menu.AppendMenu(MF_STRING,111,"hello");
    menu.AppendMenu(MF_STRING,112,"weixin");
    menu.AppendMenu(MF_STRING,113,"mybole");
    menu.Detach();  //后面加的                 |--->这里用了菜单对象的句柄,然后强制类型转换
   
    GetMenu()->GetSubMenu(0)->AppendMenu(MF_STRING,114,"Welcome");  //在文件菜单中添加菜单项
    GetMenu()->GetSubMenu(0)->InsertMenu(ID_FILE_OPEN,
                                         MF_BYCOMMAND | MF_STRING,115,"WinSun");//插入菜单项
 
17、删除菜单
    CMenu::DeleteMenu
    BOOL DeleteMenu(UINT nPosition,UINT nFlags);//
    删除哪个菜单,哪个菜单项,要看你用哪个菜单的指针去调用该函数

    GetMenu()->DeleteMenu(1,MF_BYPUSITION);
    GetMenu()->GetSubMenu(0)->DeleteMenu(ID_FILE_OPEN,MF_BYCOMMAND);

18、手动添加菜单项响应
    1 首先创建资源id
      Resource.h  -->  #define IDM_HELLO   111
    2 把原来写好的插入菜单项的代码中资源id改为定义id
      menu.AppendMenu(MF_STRING,IDM_HELLO,"hello");
    3 手工添加消息原形和消息映射
      .h 中添加消息响应函数宏 afx_msg void OnHello();  //消息原形
      .cpp 中添加消息映射 ON_COMMAND(IDM_HELLO,OnHello)  //不要加标点符号
             添加响应函数 void C****::OnHello(){}

19、前面都是在框架类中操作,直接使用GetMenu()即可获取属于框架类的菜单指针,现在在view中调用菜单,必须首先获取框架类指针,如何获取呢,可以用GetParent()获取父窗口指针的方式得到

   在非mainframe类OnCreate()中添加菜单,菜单不会立即显示,必须使用菜单重绘函数DrawMenuBar()
   CWnd::DrawMenuBar
   voidb DrawMenuBar();  //重绘菜单栏

   GetParent()->DrawMenuBar();  //在view类中对属于框架类的菜单操作,必须通过框架类指针使用
                                //否则不自动显示菜单,因为菜单栏并不属于view类

20、窗口重绘
   CWnd::Invalidate
   void Invalidate(BOOL bErase = TRUE);  //窗口重绘

21、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;

   CStringArray : CObject
   CStringArray支持CString对象数组,可动态增加
   CStringArray调用的几乎使CObArray对象的函数
   CStringArray的增加对象函数add()用的就是CObArray对象的add()函数

   CObArray::Add
   int Add(CObject* newElement);  //增加元素
  
   CObArray::GetAt
   CObject* GetAt(int nIndex)const; //取出元素

   CObArray::GetSize  //元素个数

22、重载OnCommand(),自定义处理命令消息
   CWnd::OnCommand
   virtual BOOL OnCommand(WPARAM wParam, LPARAM lParam);

   参数wParam为4字节无符号整型,前面两个字节就是低字节区,低字节区标识了命令id
   有一个宏可以取到低字节区
   WORD LOWORD{DWORD dwValue};
   取高字节区
   WORD HOWORD{DWORD dwValue}; //从一个32位的值当中获取高字节区的值

   CFrameWnd::GetActieView
   CView* GetActiveView()const; //获取当前视类的一个指针
   
   想直接通过C***View view;的方式获取已经被与mainframe等关联起来的view对象是不可能的,应该通过上面的函数获取已经存在的被与其他类关联起来的view类指针
   CMenu2View *pView=(CMenu2View)GetActiveView();  //获取当前view类的指针


 

内容概要:该研究通过在黑龙江省某示范村进行24小时实地测试,比较了燃煤炉具与自动/手动进料生物质炉具的污染物排放特征。结果显示,生物质炉具相比燃煤炉具显著降低了PM2.5、CO和SO2的排放(自动进料分别降低41.2%、54.3%、40.0%;手动进料降低35.3%、22.1%、20.0%),但NOx排放未降低甚至有所增加。研究还发现,经济性和便利性是影响生物质炉具推广的重要因素。该研究不仅提供了实际排放数据支持,还通过Python代码详细复现了排放特征比较、减排效果计算和结果可视化,进一步探讨了燃料性质、动态排放特征、碳平衡计算以及政策建议。 适合人群:从事环境科学研究的学者、政府环保部门工作人员、能源政策制定者、关注农村能源转型的社会人士。 使用场景及目标:①评估生物质炉具在农村地区的推广潜力;②为政策制定者提供科学依据,优化补贴政策;③帮助研究人员深入了解生物质炉具的排放特征和技术改进方向;④为企业研发更高效的生物质炉具提供参考。 其他说明:该研究通过大量数据分析和模拟,揭示了生物质炉具在实际应用中的优点和挑战,特别是NOx排放增加的问题。研究还提出了多项具体的技术改进方向和政策建议,如优化进料方式、提高热效率、建设本地颗粒厂等,为生物质炉具的广泛推广提供了可行路径。此外,研究还开发了一个智能政策建议生成系统,可以根据不同地区的特征定制化生成政策建议,为农村能源转型提供了有力支持。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值