zoukankan      html  css  js  c++  java
  • VC++学习(6):菜单编程


    1.       MFC中的顶层菜单默认为弹出菜单(Pop-up),它是不能用来作命令响应的,当取消Pop-up选项后可接受命令响应。


    2.       消息的分类:标准消息,命令消息,通告消息。

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

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

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

    总结:

      凡是从CWnd派生的类,既可以接收标准消息,也要以接收命令消息和通告消息。

      而对于那些从CCmdTarget派生的类,则只能接收命令消息和通告消息,不能接收标准消息。

    3.       MFC中菜单项消息如果利用ClassWizard来对菜单项消息分别在上述四个类中进行响应,则菜单消息传递顺序:View--Doc--CMainFrame--App类。菜单消息一旦在其中一个类中响应则不再在其它类中查找响应函数。

    菜单消息与前面介绍的标准消息的实现机制是相类似的,都是在消息响应函数原型(头文件),消息映射宏(源文件)和消息函数实现(源文件)中添加代码。注意:文档类与应用程序类都是由CCmndTarget类派生,所以可以接收菜单命令消息,但不能接收标准消息(只能由CWnd类派生才可以)。

    具体消息路由过程:

    当点击一个菜单项的时候,最先接受到菜单项消息的是CMainFrame框架类,CMainFrame框架类将会把菜单项消息交给它的子窗口View类,由View类首先进行处理;如果View类检测到没对该菜单项消息做响应,则View把菜单项消息交由文档类Doc进行处理;如果Doc类检测到Doc类中也没对该菜单项消息做响应,则Doc类又把该菜单项消息交还给View类,由View类再交还给CMainFrame类处理。如果CMainFrame类查看到CMainFrame中也没对该消息做响应,则最终交给App进行处理。

    4.       一个菜单栏可以有若干个子菜单,一个子菜单又可以有若干个菜单项等。对菜单栏的子菜单由左至右建立从0开始的索引。对特定子菜单的菜单项由上至下建立了从0开始的索引。访问子菜单和菜单项均可以通过其索引或标识(如果有标识的话)进行。

    相关重要函数:

    CMenu* GetMenu( ) ;//CWnd::GetMenu得到窗口菜单栏对象指针。

    CMenu* GetSubMenu( ) ;//CMenu::GetSubMenu获得指向弹出菜单对象指针

    UINT CheckMenuItem( );//CMenu::CheckMenuItem 添加选中标识

    BOOL SetDefaultItem();//CMenu::SetDefaultItem 为指定菜单设置缺省菜单项(唯一)

    BOOL SetMenuItemBitmaps( );//CMenu::SetMenuItemBitmaps 设置位图标题菜单。

    UINT EnableMenuItem();//CMenu::EnableMenuItem使菜单项有效,无效,或变灰。

    BOOL SetMenu( CMenu* pMenu );//CWnd::SetMenu在当前窗口上设置新菜单或移除菜单。

    HMENU Detach( );//CMenu::Detach;断开一个菜单资源与相关的类对象句柄关联,可以定义局部对象,在使用完后调用Detach函数,则不会因为局部对象影响使用

    说明:

    1)在计算子菜单菜单项的索引的时候,分隔栏符也算索引的。

    2int GetSystemMetrics()获取系统信息度量。可以用它来获取菜单标题的尺寸(后面还会使用到获取屏目尺寸)从而设置位图标题菜单中位图的大小。

    3)在MFCMFC为我们提供了一套命令更新机制,所有菜单项的更新都是由这套机制来完成的。所以要想利用CMenu::EnableMenuItem来自己控制菜单使用或不使用变灰等,必须要在CMainFrame的构造函数中将变量m_bAutoMenuEnable设置为FALSE

    EXAMPLE

    CMenu menu;//定义为局部对象

    menu.LoadMenu(IDR_MAINFRAME);

    SetMenu(&menu);

    menu.Detach();// 这里menu对象作为一个局部对象。使用Detach()menu对象中分离窗口菜单句柄,从而当menu对象析构的时候窗口菜单资源不随之销毁。

    5.       命令更新机制:

    菜单项状态的维护是依赖于CN_UPDATE_COMMAND_UI消息,谁捕获CN_UPDATE_COMMAND_UI消息,MFC就在其中创建一个CCmdUI对象。

    在后台操作系统发出WM_INITMENUPOPUP消息,然后由MFC的基类如CFrameWnd接管并创建一个CCmdUI对象和第一个菜单项相关联,调用对象成员函数DoUpdate()(注:这个函数在MSDN中没有找到说明)发出CN_UPDATE_COMMAND_UI消息,这条消息带有指向CCmdUI对象的指针。此后同一个CCmdUI对象又设置为与第二个菜单项相关联,这样顺序进行,直到完成所有菜单项。

    更新命令UI处理程序仅应用于弹出式菜单项上的项目,不能应用于永久显示的顶级菜单项目。

    说明:可以手工或用ClassWizard来给菜单项添加UPDATE_COMMAND_UI消息响应,利用响应函数中传进来的CCmdUI对象指针可完成设置菜单项可使用,不可使用,变灰,设置标记菜单等操作。

    6,如果要想让工具栏上的某个图标与菜单项的某个菜单相关联,只需要将图标的ID设置为该菜单项的ID。

    工具栏图标的索引记数顺序是:从左至右从0开始,分隔符也算索引号

     

    7,利用向项目中添加VC的POPMENU控件:Project->Add to Project->Components and Controls..

    系统增加的内容:A,一个菜单资源;B,在派生View类中增加了OnContextMenu()函数

    说明:

    1CWnd::OnContextMenu Called by the 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.

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

    //CMenu::TrackPopupMenu Displays a floating pop-up menu at the specified location and tracks the selection of items on the pop-up menu. A floating pop-up menu can appear anywhere on the screen.

     

    8,利用调用TrackPopupMenu函数,手工添加弹出菜单:

    1)用资源管理器添加一个菜单资源

    2)在鼠标右键消息响应函数中,加载菜单资源,并获得要显示的子菜单指针,并用该指针调用TrackPopupMenu函数便完成任务(但要注意:鼠标响应函数传进来的坐标是客户区坐标,而TrackPopupMenu函数中使用的是屏幕坐标,在调用TrackPopupMenu前要调用ClientToScreen客户区坐标到屏幕坐标的转换

    事例代码:

    CMenu menu;

    menu.LoadMenu(IDR_MENU1);

    CMenu *pPopup=menu.GetSubMenu(0);

    ClientToScreen(&point);                  //坐标转换

    pPopup->TrackPopupMenu(TPM_LEFTALIGN | TPM_RIGHTBUTTON, point.x, point.y,this);

    说明:

    CWnd::ClientToScreen(..);//将一个坐标点或一个矩形区域坐标转换成屏幕坐标。

    CMenu::TrackPopupMenu(..);//在指定位置以指定的方式显示弹出菜单。

     

    9,当弹出菜单属于框架窗口的时候(可在TrackPopupMenu函数参数中设置),弹出菜单上的消息,在路由的时候,仍然遵循View-DOC-MainFrame-APP的响应顺序。

    10,动态菜单编程:

    所有的资源对象都有一个数据成员保存了资源的句柄。

    下面的函数可以操作子菜单(Popup菜单)或者菜单项;

    CMenu::AppendMenu //Appends a new item to the end of a menu.

    CMenu::CreatePopupMenu //Creates an empty pop-up menu and attaches it to a CMenu object.

    CMenu::InsertMenu

    //Inserts a new menu item at the position specified by nPosition and moves other items down the menu.

    CMenu::GetSubMenu //Retrieves a pointer to a pop-up menu.

    CWnd::GetMenu //Retrieves a pointer to the menu for this window.

    CMenu::DeleteMenu //Deletes an item from the menu.

     

    11,手动给动态菜单项添加响应函数:

    Resource.h中可以添加资源的ID

    在头文件中写消息函数原型

    在代码文件中添加消息映射和添加消息响应函数

    说明:

    可以先创建一个临时的菜单项,设置它的ID和动态菜单项的一致,然后对它用向导进行消息响应,然后删除临时菜单。

    再在代码文件中把消息映射放到宏外(注意一定要放到宏外面,因为CLASSWIZARD发现菜单删除了,同时要把其宏对里的消息映射也删除掉的)

     

    12,CWnd::DrawMenuBar   重画菜单栏

    //Redraws the menu bar. If a menu bar is changed after Windows has created the window, call this function to draw the changed menu bar

     

    CWnd::GetParent //get a pointer to a child window’s parent window (if any).

    CWnd::Invalidate //注意其参数的作用,使窗口区域无效,重画时擦出原来的背景(也可以有效)

     

    13,集合类:

    CStringArrayCStringArrayCDWordArrayCPtrArrayCStringArrayCUIntArrayCWordArray

    其中成员函数:

    CArray::GetAt

    CArray::Add

     

    14,命令消息是到OnCommand函数的时候完成路由的。

    由于CWnd::OnCommand 是个虚函数,可以在框架类中重写OnCommand函数,从而可以截获菜单消息使它不再往下(VIEW类)路由。

    例:

    BOOL CMainFrame::OnCommand(WPARAM wParam, LPARAM lParam)

    {

     // TODO: Add your specialized code here and/or call the base class

     int MenuCmdId=LOWORD(wParam);//取命令ID

     CMenu2View *pView=(CMenu2View*)GetActiveView();//获取当前VIEW类指针

     if(MenuCmdId>=IDM_PHONE1 && MenuCmdId<IDM_PHONE1+pView->m_strArray.GetSize())//消息范围判断

     {

     CClientDC dc(pView);

     dc.TextOut(0,0,pView->m_strArray.GetAt(MenuCmdId-IDM_PHONE1));

     return TRUE;

       //函数返回,避免调用CFrameWnd::OnCommand函数,在CFrameWnd::OnCommand中截获的消息会交由VIEW类处理

     }

     return CFrameWnd::OnCommand(wParam, lParam);

     //调用基类OnCommand函数,在CFrameWnd::OnCommand中截获的消息会交由VIEW类处理

    }

     

    15,LOWORD与HIWORD宏

    WORD LOWORD(

     DWORD dwValue // value from which low-order word is retrieved

    );

    WORD HIWORD(

     DWORD dwValue // value from which high-order word is retrieved

    );

     

    //The LOWORD macro retrieves the low-order word from the given 32-bit value.

    //The HIWORD macro retrieves the high-order word from the given 32-bit value.

     

    16,CFrameWnd::GetActiveView

    CView* GetActiveView( ) const;//获取当前视窗口指针(单文档框架中)

    源文件是单独参与编译的。

     

  • 相关阅读:
    Element Plus表单resetFields重置表单无效
    thinkphp6通过中间件设置跨域
    centos7安装jdk
    面试
    行测-逻辑填空
    行测-语句表达
    行测-片段阅读
    行测-四大文明古国
    基于 OAuth2.0 协议的单点登录系统方案设计
    性能测试知识点+流程
  • 原文地址:https://www.cnblogs.com/forlina/p/2119751.html
Copyright © 2011-2022 走看看