vc学习笔记

资源的添加:右键ResourceView->插入,可选择各类型资源。
VC组件(如右键菜单)或其它系统已经安装的ActiveX控件(如Canldar)的添加:Project->Add to Project->Components and Controls..
在dialog上右键,insert ActiveX

1、添加工具条(或菜单等其它资源):
右键ResourceView->插入,选择插入的资源类型,命名其ID等属性。然后在该资源上右键->建立类向导(或Ctrl+DBClick),然后选择一个已经存在的类(也可新建类)如CMainFrame,这时可选择对应ID,为其创建事件。 
在MainFrm.h的Protect中加入:CToolBar m_wndToolBar2;
在MainFrm.cpp的OnCreat事件中加入:
    if (!m_wndToolBar2.CreateEx(this) ||
        !m_wndToolBar2.LoadToolBar(IDR_MyID))//你创建的工具栏ID
    {
        TRACE0("Failed to create toolbar/n");
        return -1;      // fail to create
    }
    m_wndToolBar2.SetBarStyle(m_wndToolBar2.GetBarStyle() |
        CBRS_TOOLTIPS | CBRS_FLYBY);
可以为新建的工具条设置样式(加在MainFrm.h上面的语句后面):
   m_wndToolBar.EnableDocking(CBRS_ALIGN_ANY);
    m_wndToolBar2.EnableDocking(CBRS_ALIGN_ANY);
    EnableDocking(CBRS_ALIGN_ANY);
    DockControlBar(&m_wndToolBar);
    DockControlBar(&m_wndToolBar2);
可以控制工具条的显示:showControlBar(&m_wndToolBar2, FALSE, FALSE);

2、右键弹出菜单(各方法有些实质是一样的):
方法一(最简单的方法):
Project->Add to Project->Components and Controls..
在visual C++ Components下选择pop-up menu,然后依次命名其ID,选择其"Add pop-up menu to"
方法二:
简单的方法你可以从工具栏上拖个ContextMenu控件下来,并编辑好,然后把你所需要添加ContextMenu的控件的ContextMenu属性设为这个右键菜单。
方法三:
除了上贴所述的方法,您也可以通过手工添写代码来实现弹出式菜单。关键的类是ContextMenu类。该类有两个构造函数,其中ContextMenu()生成一个不含任何菜单项的弹出式菜单;ContextMenu(MenuItem[] menus)生成一个包括参数中所指定的菜单项的弹出式菜单。如要给一个按钮控件button1添加弹出式菜单,可以参考以下的代码:
ContextMenu Menu1=new ContextMenu();
Menu1.MenuItems.Add(new MenuItem(“弹出菜单一"));
Menu1.MenuItems.Add(new MenuItem(“弹出菜单二"));
button1.ContextMenu=Menu1;
ContextMenu有几个关键的属性、方法和事件,可以帮助您定制弹出式菜单,属性RightToLeft可以使菜单项从右到左对齐,属性SourceControl返回一个Control值表示当前所显示弹出菜单对应的控件。Show()方法可以使程序主动显示弹出菜单。当弹出菜单弹出时将引发一个Popup事件,你可以在该事件的响应方法中进行一些处理使弹出菜单显示前做一些操作。
参考MSDN中给出的一个示例来定制弹出式菜单:
http://msdn.microsoft.com/library/default.asp?url=/library/en-us/cpref/html/frlrfSystemWindowsFormsContextMenuClassTopic.asp
方法四:
利用调用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(..);//在指定位置以指定的方式显示弹出菜单。
CWnd::ScreenToClient(..);
//Converts the screen coordinates of a given point or rectangle on the display to client coordinates.
说明:至少有两类方法,一种是右键鼠标消息来处理,另一种是处理WM_CONTEXTMENU窗口消息(推荐使用)。范例代码如下:IDR_GISPROPERTY为指定的菜单资源。
a.右键鼠标消息
void CRightView::OnRButtonDown(UINT nFlags, CPoint point)
{

    // TODO: Add your message handler code here and/or call default
    CMenu menuMain;
    if(!menuMain.LoadMenu(IDR_GISPROPERTY))
        return;
    CMenu* pRecordMenu = menuMain.GetSubMenu(2);    
    ASSERT(pRecordMenu);
    ClientToScreen(&point);
    pRecordMenu->TrackPopupMenu(TPM_LEFTALIGN |TPM_LEFTBUTTON, point.x,
      point.y, this);

    CScrollView::OnRButtonDown(nFlags, point);
}
b.处理WM_CONTEXTMENU窗口消息
void CRightView::OnContextMenu(CWnd* pWnd, CPoint point)
{
    // TODO: Add your message handler code here
    CMenu menuMain;
    if(!menuMain.LoadMenu(IDR_GISPROPERTY))
        return;
    CMenu* pRecordMenu = menuMain.GetSubMenu(2);    
    ASSERT(pRecordMenu);
    pRecordMenu->TrackPopupMenu(TPM_LEFTALIGN | TPM_LEFTBUTTON| TPM_RIGHTBUTTON, point.x,
      point.y, this);

}
 
3、菜单的Check
  poMenu->CheckMenuItem(ID_VIEW_FORMATTOOLBAR,MF_CHECKED);

4、Dialog窗体的菜单:在Dialog上右键,属性->即可选择菜单。

5、显示对话框:新建一个对话框,在其上右键->建立类向导,新建一个MyDlg的类,
然后在主窗体的cpp文件(如MainFrm.cpp)中加入#include "MyDlg.h",就可以在程序中引用了,如:
模式显示:
  MyDlg dlg;
  dlg.DoModal();
无模式显示:


以下为摘录部分:
1、SDK-菜单详解
接着上一天的内容,添加一个菜单,并加入各项,用记事本打开resource.rc,可以找到如下内容
IDR_MENU1 MENU DISCARDABLE   //这里定义菜单名
BEGIN
    MENUITEM "Exit",                        IDM_EXIT  //添加菜单项EXIT
    POPUP "Edit"                //添加弹出菜单
    BEGIN
        MENUITEM "Copy(&C)/tCtrl+C", IDM_COPY
        MENUITEM "Paste",  IDM_PASTE
        MENUITEM SEPARATOR
        MENUITEM "SeleceAll",  IDM_SELECTALL
    END
    MENUITEM "About", IDM_ABOUT
END
同时在resource.h中可以找到IDM_EXIT等的定义
#define IDM_EXIT                        40001
#define IDM_COPY                        40002
#define IDM_PASTE                       40003
#define IDM_SELECTALL                   40004
#define IDM_ABOUT                       40005
#define IDM_ALIGNLEFT                                40006
#define IDM_ALIGNRIGHT                             40007
这样就把菜单资源和我们的主程序关联起来了。
接着就要把菜单在窗口中显示出来,我们可以在初始化窗口时指定菜单
wndclass.lpszMenuName=(LPCSTR)IDR_MENU1;
这样编译,运行就可以看到菜单出现在主窗口上部了
菜单项的消息响应:
菜单消息归类于WM_COMMAND,而对于特定的菜单项,有相应的消息值跟他对应,所以只要对WM_COMMAND消息进行进一步的分流,就可以添加各个菜单的消息响应。具体代码如下:
case WM_COMMAND:
              wparam=LOWORD(wParam);
              switch(wparam)
              {
              case IDM_EXIT:
                     PostQuitMessage(0);
                     return 0;
              case IDM_COPY:
                     MessageBox(hwnd,"Copy Content","Menu",MB_OK);
                     return 0;
              case IDM_PASTE:
                     MessageBox(hwnd,"Paste Content","Menu",MB_OK);
                     return 0;
              case IDM_SELECTALL:
                     MessageBox(hwnd,"Select All Content","Menu",MB_OK);
                     return 0;
              case IDM_ABOUT:
                     MessageBox(hwnd,"About: Designed by csenior","Menu",MB_OK);
                     return 0;
              }
              Break;
另外还有一种创建菜单的方式:利用CreateMenu,CreatePopupMenu,GetMenu,InsertMenu,AppendMenu函数,我们试着在WM_CREATE消息中添加如下代码:
case WM_CREATE:
              HMENU hMainMenu;
              HMENU hAddMenu;
              hMainMenu=GetMenu(hwnd);
              hAddMenu=CreatePopupMenu();
              InsertMenu(hMainMenu,2,MF_BYPOSITION | MF_STRING | MF_POPUP,(UINT)hAddMenu,"格式");
              AppendMenu(hAddMenu,MF_STRING,IDM_ALIGNLEFT,"Left Align");
              AppendMenu(hAddMenu,MF_STRING,IDM_ALIGNRIGHT,"Right Align");
编译运行,可以看到多了个菜单条。
这里GetMenu(hwnd)获得hwnd窗口的菜单。然后通过InsertMenu把之前创建的hAddMenu连接到hMainMenu上去。最后添加各子菜单项
之前在CreateWindow创建窗口时,倒数第三个参数就是HMENU结构,试着在这里给他赋一个值:
HMENU hMenu,hCMenu1,hCMenu2,hCMenu3;
       hMenu=CreateMenu();
       hCMenu1=CreatePopupMenu();
       hCMenu2=CreatePopupMenu();
       hCMenu3=CreatePopupMenu();
       InsertMenu(hMenu,0,MF_BYPOSITION | MF_STRING | MF_POPUP,(UINT)hCMenu1,"File");
       InsertMenu(hMenu,1,MF_BYPOSITION | MF_STRING | MF_POPUP,(UINT)hCMenu2,"View");
       InsertMenu(hMenu,2,MF_BYPOSITION | MF_STRING | MF_POPUP,(UINT)hCMenu3,"Edit");
       AppendMenu(hMenu,MF_STRING,(UINT)41001,"About");
       AppendMenu(hCMenu1,MF_STRING,(UINT)41002,"Open");
       AppendMenu(hCMenu1,MF_STRING,(UINT)41003,"Close");
       AppendMenu(hCMenu2,MF_STRING,(UINT)41004,"Big");
       AppendMenu(hCMenu2,MF_STRING,(UINT)41005,"Small");
       AppendMenu(hCMenu3,MF_STRING,(UINT)41006,"Copy");
       AppendMenu(hCMenu3,MF_STRING,(UINT)41007,"Paste");
       hWnd=CreateWindow("HelloWin",wintitle,WS_OVERLAPPEDWINDOW,CW_USEDEFAULT,
              CW_USEDEFAULT,CW_USEDEFAULT,CW_USEDEFAULT,NULL,hMenu,hInstance,NULL);
运行,我们可以看到菜单变了,因此在此处也可以添加修改程序的菜单,但是这里不能用GetMenu,因为hWnd窗口句柄还没被实例化
关于菜单命令的消息参数说明下:
基本参数说明:
    wNotifyCode=HIWORD(wParam)1
    WID=LOWORD(wParam);
    hWndCtl=(HWND)1Param”;
    当WM_CoMMAND命令是由选择菜单命令产生时WNotifycode参数为0,wID参数
为菜单项的标识导,hwndctl参数为NULL。
    当WM_COMMAND命今是来自于快捷键时WNotifycode参数为1 WID是快捷键标
识号,hWndCtl参数为NULL。
    如果是因为控件向父窗口发出通知消息面产生WM—COMMAND消息时。
WNotifycode参数为通知代码,wID为控件标识号,hwndctl参数为控件句柄。
通过EnabaleMenuItem,EnableMenuRadioItem,可以设置菜单项的状态为有效,无效,灰色三种,同时可以调用CheckMenuItem,CheckMenuRadioItem来改变菜单项的选种状态具体如下代码:
              EnableMenuItem(hMainMenu,IDM_EXIT,MF_BYCOMMAND | MF_GRAYED);
              EnableMenuItem(hAddMenu,1,MF_BYPOSITION | MF_GRAYED);
              CheckMenuItem(hMainMenu,IDM_COPY,MF_BYCOMMAND |MF_CHECKED);          CheckMenuRadioItem(hAddMenu,IDM_ALIGNLEFT,IDM_ALIGNRIGHT,IDM_ALIGNLEFT,MF_BYCOMMAND);

2、孙鑫VC++讲座笔记-(6)菜单编程
1,弹出菜单(Pop-up)是不能用来作命令响应的。

2,MFC中菜单项消息如果利用ClassWizard来对菜单项消息分别在上述四个类中进行响应,则菜单消息传递顺序:View类--Doc类--CMainFrame类--App类。菜单消息一旦在其中一个类中响应则不再在其它类中查找响应函数。
具体:
当点击一个菜单项的时候,最先接受到菜单项消息的是CMainFrame框架类,CMainFrame框架类将会把菜单项消息交给它的子窗口View类,由View类首先进行处理;如果View类检测到没对该菜单项消息做响应,则View类把菜单项消息交由文档类Doc类进行处理;如果Doc类检测到Doc类中也没对该菜单项消息做响应,则Doc类又把该菜单项消息交还给View类,由View类再交还给CMainFrame类处理。如果CMainFrame类查看到CMainFrame类中也没对该消息做响应,则最终交给App类进行处理。

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

4,一个菜单拦可以有若干个子菜单,一个子菜单又可以有若干个菜单项等。对菜单栏的子菜单由左至右建立从0开始的索引。对特定子菜单的菜单项由上至下建立了从0开始的索引。访问子菜单和菜单项均可以通过其索引或标识(如果有标识的话)进行。
相关重要函数:
CMenu* GetMenu( ) ;//CWnd::GetMenu得到窗口菜单栏对象指针。
CMenu* GetSubMenu(  ) ;//CMenu::GetSubMenu获得指向弹出菜单对象指针
UINT CheckMenuItem( );//CMenu::CheckMenuItem Adds check marks to or removes check marks from menu items in the pop-up menu.
BOOL SetDefaultItem();//CMenu::SetDefaultItem Sets the default menu item for the specified menu.
BOOL SetMenuItemBitmaps( );//CMenu::SetMenuItemBitmaps 设置位图标题菜单。
UINT EnableMenuItem();//CMenu::EnableMenuItem使菜单项有效,无效,或变灰。
BOOL SetMenu( CMenu* pMenu );//CWnd::SetMenu在当前窗口上设置新菜单或移除菜单。
HMENU Detach( );//CMenu::Detach Detaches a Windows menu from a CMenu object and returns the handle.
说明:
1)在计算子菜单菜单项的索引的时候,分隔栏符也算索引的。
2)int GetSystemMetrics()获取系统信息度量。可以用它来获取菜单标题的尺寸从而设置位图标题菜单中位图的大小。
3)在MFC中MFC为我们提供了一套命令更新机制,所有菜单项的更新都是由这套机制来完成的。所以要想利用CMenu::EnableMenuItem来自己控制菜单使用或不使用变灰等,必须要在CMainFrame的构造函数中将变量m_bAutoMenuEnable设置为FALSE。
4)Create a CMenu object on the stack frame as a local, then call CMenu’s member functions to manipulate the new menu as needed. Next, call CWnd::SetMenu to set the menu to a window, followed immediately by a call to the CMenu object’s Detach member function. The CWnd::SetMenu member function sets the window’s menu to the new menu, causes the window to be redrawn to reflect the menu change, and also passes ownership of the menu to the window. The call to Detach detaches the HMENU from the CMenu object, so that when the local CMenu variable passes out of scope, the CMenu object destructor does not attempt to destroy a menu it no longer owns. The menu itself is automatically destroyed when the window is destroyed.
5)You can use the LoadMenuIndirect member function to create a menu from a template in memory, but a menu created from a resource by a call to LoadMenu is more easily maintained, and the menu resource itself can be created and modified by the menu editor.
6)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处理程序仅应用于弹出式菜单项上的项目,不能应用于永久显示的顶级菜单项目。
说明:
1)可以手工或用ClassWizard来给菜单项添加UPDATE_COMMAND_UI消息响应,利用响应函数中传进来的CCmdUI对象指针可完成设置菜单项可使用,不可使用,变灰,设置标记菜单等操作。

6,如果要想让工具栏上的某个图标与菜单项的某个菜单相关联,只需要将图标的ID设置为该菜单项的ID。
工具栏图标的索引记数顺序是:从做至右从0开始,分隔符也算索引号。

7,利用向项目中添加VC的POPMENU控件:Project->Add to Project->Components and Controls..
系统增加的内容:A,一个菜单资源;B,在派生View类中增加了OnContextMenu()函数
说明:
1)CWnd::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.
2)BOOL 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(..);//在指定位置以指定的方式显示弹出菜单。
CWnd::ScreenToClient(..);
//Converts the screen coordinates of a given point or rectangle on the display to client coordinates.

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

10,动态菜单编程:
所有的资源对象都有一个数据成员保存了资源的句柄。
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,集合类:
CStringArray,CStringArray,CDWordArray,CPtrArray,CStringArray,CUIntArray,CWordArray
其中成员函数:
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类处理
}
 
MSDN说明:
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 processes the message map for control notification and ON_COMMAND entries, and calls the appropriate member function.
Override this member function in your derived class to handle the WM_COMMAND message. An override will not process the message map unless the base class OnCommand is called.

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;//获取当前视窗口指针(单文档框架中)

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



Lesson6 菜单 ---孙鑫VC++教程

Lesson6 菜单
state:finished

1.AfxMessageBox应用程序框架的MessageBox函数

2.接收菜单命令消息的顺序,View类->Doc类->MainFrame类->App类

3.消息的分类:
 标准消息
    除WM_COMMAND之外,所有以WM_开头的消息。
    从CWnd派生的类,都可以接收到这类消息。
 命令消息
    来自菜单、加速键或工具栏按钮的消息。这类消息都以WM_COMMAND呈现。
    在MFC中,通过菜单项的标识(ID)来区分不同的命令消息;在SDK中,
    通过消息的wParam参数识别。
    从CCmdTarget派生的类,都可以接收到这类消息。(CWnd是CCmdTarget类的子类)
 通告消息
    由控件产生的消息,例如,按钮的单击,列表框的选择等均产生此类消息,
    为的是向其父窗口(通常是对话框)通知事件的发生。这类消息也是以
    WM_COMMAND形式呈现。
    从CCmdTarget派生的类,都可以接收到这类消息。
4.源代码的变化
  MenuView.h
  ------------------------------------------------------------------------------------
  protected:
 //{{AFX_MSG(CMenuView)
 afx_msg void OnTest();                  //命令消息处理函数原型的声明
 //}}AFX_MSG
 DECLARE_MESSAGE_MAP()
  -------------------------------------------------------------------------------------
  MenuView.CPP
  -------------------------------------------------------------------------------------
  BEGIN_MESSAGE_MAP(CMenuView, CView)
 //{{AFX_MSG_MAP(CMenuView)
 ON_COMMAND(IDM_TEST, OnTest)            //使用ON_COMMAND宏将我们的菜单ID和消息
 //}}AFX_MSG_MAP                         //响应函数联系起来
 // Standard printing commands
 ON_COMMAND(ID_FILE_PRINT, CView::OnFilePrint)
 ON_COMMAND(ID_FILE_PRINT_DIRECT, CView::OnFilePrint)
 ON_COMMAND(ID_FILE_PRINT_PREVIEW, CView::OnFilePrintPreview)
  END_MESSAGE_MAP()
  ---------------------------------------------------------------------------------------
5.创建标记菜单
 CWnd::GetMenu
 MSDN
 -----------------------------------------------------------------------------------------
 CWnd::GetMenu
 Retrieves a pointer to the menu for this window.
   
    CMenu* GetMenu( ) const;  //获取框架窗口菜单栏的指针
 ---------------------------------------------------------------------------------------
    CMenu派生自CObject,封装了和菜单有关的操作,封装了一个菜单句柄
 CMenu::GetSubMenu
 MSDN
 -----------------------------------------------------------------------------------------
 CMenu::GetSubMenu                 //返回子菜单的操作
    Retrieves the CMenu object of a pop-up menu.

 CMenu* GetSubMenu(
    int nPos                              //弹出菜单的位置
 ) const;
 ----------------------------------------------------------------------------------------
 CMenu::CheckMenuItem
 MSDN
 --------------------------------------------------------------------------------------
 CMenu::CheckMenuItem
 Adds check marks to or removes check marks from menu items in the pop-up menu.

 UINT CheckMenuItem(
    UINT nIDCheckItem,
    UINT nCheck
 );
 nIDCheckItem
    Specifies the menu item to be checked, as determined by nCheck.
    nCheck
       Specifies how to check the menu item and how to determine the item's position in the
    menu. The nCheck parameter can be a combination of MF_CHECKED or MF_UNCHECKED with
    MF_BYPOSITION or MF_BYCOMMAND flags. These flags can be combined by using the bitwise
    OR operator. They have the following meanings:
    MF_BYCOMMAND   Specifies that the parameter gives the command ID of the existing menu
                item. This is the default.
    MF_BYPOSITION  Specifies that the parameter gives the position of the existing menu
                 item. The first item is at position 0.
    MF_CHECKED     Acts as a toggle with MF_UNCHECKED to place the default check mark next
                to the item.
    MF_UNCHECKED   Acts as a toggle with MF_CHECKED to remove a check mark next to the item.
 ---------------------------------------------------------------------------------------

 加上选择标记:
 MainFrm.cpp
 
 --------------------------------------------------------------------------------------
 int CMainFrame::OnCreate(LPCREATESTRUCT lpCreateStruct)
 {
  //GetMenu()->GetSubMenu(0)->CheckMenuItem(0,MF_BYPOSITION | MF_CHECKED);
  GetMenu()->GetSubMenu(0)->CheckMenuItem(ID_FILE_NEW,MF_BYPOSITION | MF_CHECKED);
 }
 --------------------------------------------------------------------------------------

6.创建缺省的菜单项
   CMenu::SetDefaultItem
   MSDN
   -----------------------------------------------------------------------------------------
   CMenu::SetDefaultItem
 Sets the default menu item for the specified menu.

 BOOL SetDefaultItem(
    UINT uItem,
    BOOL fByPos = FALSE
 );
   ----------------------------------------------------------------------------------------
   MainFrm.cpp
 
 --------------------------------------------------------------------------------------
 int CMainFrame::OnCreate(LPCREATESTRUCT lpCreateStruct)
 {
  GetMenu()->GetSubMenu(0)->SetDefaultItem(1,TRUE);
  //GetMenu()->GetSubMenu(0)->SetDefaultItem(ID_FILE_OPEN);
 }
 --------------------------------------------------------------------------------------
 一个子菜单项中不能有两个缺省的菜单

7.图形标记菜单的创建
CMenu::SetMenuItemBitmaps
MSDN
  ----------------------------------------------------------------------------------------
   CMenu::SetMenuItemBitmaps
 Associates the specified bitmaps with a menu item.

 BOOL SetMenuItemBitmaps(
    UINT nPosition,
    UINT nFlags,                        //MF_BYCOMMAND or MF_BYPOSITION
    const CBitmap* pBmpUnchecked,       //标记取消时候显示的位图
    const CBitmap* pBmpChecked          //点中的时候显示的位图
 );
  ------------------------------------------------------------------------------------------
  获取图形标记菜单标记的大小
  GetSystemMetrics
  -----------------------------------------------------------------------------------------
  MSDN
  GetSystemMetrics
 The GetSystemMetrics function retrieves various system metrics (widths and heights of
 display elements) and system configuration settings. All dimensions retrieved by
 GetSystemMetrics are in pixels.

 int GetSystemMetrics(
   int nIndex                  //SM_CXMENUCHECK, SM_CYMENUCHECK Dimensions of the default
 );                            //menu check-mark bitmap, in pixels.
 
  ------------------------------------------------------------------------------------------

8.使菜单项失效
  CMenu::EnableMenuItem
  MSDN
  --------------------------------------------------------------------------------------------
  CMenu::EnableMenuItem
 Enables, disables, or dims a menu item.

 UINT EnableMenuItem(
    UINT nIDEnableItem,    
    UINT nEnable  //MF_BYCOMMAND or MF_BYPOSITIONMF_DISABLED, MF_ENABLED, or MF_GRAYED
 );

 // NOTE: m_bAutoMenuEnable is set to FALSE in the constructor of
 // CMainFrame so no ON_UPDATE_COMMAND_UI or ON_COMMAND handlers are
 // needed, and CMenu::EnableMenuItem() will work as expected.
    // 需要在CMainFrame的构造函数中写入 m_bAutoMenuEnable=FALSE 才能更新菜单,使上面的命令生效
  ---------------------------------------------------------------------------------------------
  MainFrm.cpp
 
 --------------------------------------------------------------------------------------
 int CMainFrame::OnCreate(LPCREATESTRUCT lpCreateStruct)
 {
  GetMenu()->GetSubMenu(0)->EnableMenuItem(ID_FILE_OPEN,MF_BYCOMMAND | MF_DISABLED
                                        | MF_GRAYED);
 }
 --------------------------------------------------------------------------------------

9.取消系统菜单
  CWnd::SetMenu
  MSDN
  ---------------------------------------------------------------------------------------------
  CWnd::SetMenu
 Sets the current menu to the specified menu.

 BOOL SetMenu(
    CMenu* pMenu
 );
  -------------------------------------------------------------------------------------------
  MainFrm.cpp
 
 --------------------------------------------------------------------------------------
 int CMainFrame::OnCreate(LPCREATESTRUCT lpCreateStruct)
 {
   SetMenu(NULL);

   CMenu menu;
   menu.LoadMenu(IDR_MAINFRAME);
   SetMenu(&menu);
   menu.Detach();      //将句柄与C++局部变量断开

 }
 --------------------------------------------------------------------------------------

10. MFC对菜单项采用的命令更新机制
 菜单项状态的维护是依赖于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处理程序仅应用于弹出式菜单项上的项目,不能应用于永久显示的顶级菜单项目。
 CCmdUI::Enable
 MSDN
 ----------------------------------------------------------------------------------------
 CCmdUI::Enable
  Call this member function to enable or disable the user-interface item for this
  command.

  virtual void Enable(
     BOOL bOn = TRUE
  );
  Parameters
   bOn
   TRUE to enable the item, FALSE to disable it.
 -----------------------------------------------------------------------------------------

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

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

  if (0 == pCmdUI->m_nIndex)   //工具栏的图标和菜单项是使用ID相关联的
  {                            //最好使用ID,而不使用索引
   pCmdUI->Enable(FALSE);
  }
 
 }
 --------------------------------------------------------------------------------------

11.增加右键弹出菜单

   step1: Project->Add To Project->Components and Controls->
          Visual C++ Components->Pop-up Menu
 
   变化:1. 在资源项中加入了弹出菜单
        2. 在CMenuView类中加入OnContextMenu(CWnd*, CPoint point)函数
 CWnd::OnContextMenu
 MSDN
 --------------------------------------------------------------------------------------
 CWnd::OnContextMenu
  Called by the framework when the user has clicked the right mouse button
        (right clicked) in the window.

  afx_msg void OnContextMenu(
     CWnd* pWnd,
     CPoint pos
  );

 Remarks
  You can process this message by displaying a context menu using the TrackPopupMenu.
 ---------------------------------------------------------------------------------------
 CMenu::TrackPopupMenu
 MSDN
 ---------------------------------------------------------------------------------------
 CMenu::TrackPopupMenu
  Displays a floating pop-up menu at the specified location and tracks the selection
  of items on the pop-up menu.

  BOOL TrackPopupMenu(
     UINT nFlags,             //弹出菜单时菜单显示的位置(相对鼠标的位置)
     int x,                   //鼠标点击的位置坐标
     int y,
     CWnd* pWnd,              //弹出菜单的拥有者
     LPCRECT lpRect = 0       //指示一个矩形的区域,在这个矩形区域内点击,弹出菜单不消失
  );                          //在矩形区域之外点击弹出菜单消失
    -----------------------------------------------------------------------------------------
 CWnd::ClientToScreen
 MSDN
 ------------------------------------------------------------------------------------------
 CWnd::ClientToScreen
 Converts the client coordinates of a given point or rectangle on the display to
 screen coordinates.

  void ClientToScreen(
     LPPOINT lpPoint
  ) const;
  void ClientToScreen(
     LPRECT lpRect
  ) const;
    -------------------------------------------------------------------------------------------
 MenuView.cpp
 -------------------------------------------------------------------------------------------
 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);//让View窗口拥有弹出菜单
  pPopup->TrackPopupMenu(TPM_LEFTALIGN | TPM_RIGHTBUTTON, point.x, point.y,
        GetParent());  //让框架窗口拥有弹出菜单
  CView::OnLButtonDown(nFlags, point);
 }

 //DEL void CMenuView::OnShow()
 //DEL {
 //DEL  // TODO: Add your command handler code here
 //DEL  MessageBox("View Show!");
 //DEL }

 void CMenuView::OnShow()
 {
  // TODO: Add your command handler code here
  MessageBox("View Show!");
 }
 -------------------------------------------------------------------------------------------------
    小结:消息总是先由顶层窗口响应,如果顶层窗口类没有消息响应函数,则立即交由底层窗口类响应

12.添加修改删除动态菜单
   (1)动态添加菜单
   CMenu::AppendMenu
   MSDN
   -------------------------------------------------------------------------------------------------
 CMenu::AppendMenu //可以将菜单或菜单项添加到现有菜单的末尾
  Appends a new item to the end of a menu.

  BOOL AppendMenu(
     UINT nFlags,       //MF_POPUP 表示添加的是弹出菜单,MF_SEPARATOR分隔栏,MF_STRING 字符串
     UINT_PTR nIDNewItem = 0, //新菜单项的命令ID
     LPCTSTR lpszNewItem = NULL //指示菜单的名称
  );
  BOOL AppendMenu(
     UINT nFlags,
     UINT_PTR nIDNewItem,
     const CBitmap* pBmp
  );
   ----------------------------------------------------------------------------------------------------
 (2)创建弹出菜单
 CMenu::CreatePopupMenu
 MSDN
 ---------------------------------------------------------------------------------------------------
 CMenu::CreatePopupMenu
  Creates a pop-up menu and attaches it to the CMenu object.

  BOOL CreatePopupMenu( );
    ---------------------------------------------------------------------------------------------------
 MainFrm.cpp
 
 --------------------------------------------------------------------------------------
 int CMainFrame::OnCreate(LPCREATESTRUCT lpCreateStruct)
 {
   CMenu menu;
   menu.CreatePopupMenu();
   GetMenu()->AppendMenu(MF_POPUP,(UINT)menu.m_hMenu,"VC");
   menu.Detach();      //将句柄与C++局部变量断开
 }
 --------------------------------------------------------------------------------------

 (3)插入菜单
 CMenu::InsertMenu
 MSDN
 -----------------------------------------------------------------------------------------
 CMenu::InsertMenu
  Inserts a new menu item at the position specified by nPosition and moves other items
  down the menu.

  BOOL InsertMenu(
     UINT nPosition,
     UINT nFlags,            //MF_BYCOMMAND or MF_BYPOSITION
     UINT_PTR nIDNewItem = 0,
     LPCTSTR lpszNewItem = NULL
  );
  BOOL InsertMenu(
     UINT nPosition,
     UINT nFlags,
     UINT_PTR nIDNewItem,
     const CBitmap* pBmp
  );
   -------------------------------------------------------------------------------------------
 (4)在弹出菜单增加菜单项
 -------------------------------------------------------------------------------------------
 MainFrm.cpp
 
 --------------------------------------------------------------------------------------
 int CMainFrame::OnCreate(LPCREATESTRUCT lpCreateStruct)
 {
   CMenu menu;
   menu.CreatePopupMenu();

   //GetMenu()->AppendMenu(MF_POPUP,(UINT)menu.m_hMenu,"VC");
   GetMenu()->InsertMenu(2,MF_BYPOSITION | MF_POPUP,(UINT)menu.m_hMenu,"VC");
   menu.AppendMenu(MF_STRING,111,"Hello");
   menu.AppendMenu(MF_STRING,112,"VC");
   menu.AppendMenu(MF_STRING,113,"MFC");//添加3个菜单项

   GetMenu()->GetSubMenu(0)->AppendMenu(MF_STRING,114,"Close");//在文件菜单添加菜单项
   GetMenu()->GetSubMenu(0)->InsertMenu(ID_FILE_OPEN,MF_BYCOMMAND |
    MF_STRING,115,"Windows");//在打开与新建之间加入菜单项
   menu.Detach();      //将句柄与C++局部变量断开
 }
 --------------------------------------------------------------------------------------

 (5)删除子菜单
 CMenu::DeleteMenu
 MSDN
 -----------------------------------------------------------------------------------------
 CMenu::DeleteMenu
  Deletes an item from the menu.

  BOOL DeleteMenu(
     UINT nPosition,
     UINT nFlags         //MF_BYCOMMAND or MF_BYPOSITION
  );
 -----------------------------------------------------------------------------------------
 MainFrm.cpp
 
 --------------------------------------------------------------------------------------
 int CMainFrame::OnCreate(LPCREATESTRUCT lpCreateStruct)
 {
  CMenu menu;
  menu.CreatePopupMenu();

  GetMenu()->DeleteMenu(1,MF_BYPOSITION); //删除编辑菜单
  GetMenu()->GetSubMenu(0)->DeleteMenu(ID_FILE_OPEN,MF_BYCOMMAND);//删除文件菜单的打开项
  menu.Detach();      //将句柄与C++局部变量断开
 }
 --------------------------------------------------------------------------------------

 (6)对动态添加的菜单项进行命令响应
 step1:在Resource.h中添加资源ID
 Resource.h
 ----------------------------------------------------------------
 #define IDM_HELLO     111
 ----------------------------------------------------------------
 step2:在头文件中添加命令响应函数原型
 MainFrm.h
 ---------------------------------------------------------------------------
 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()
 ----------------------------------------------------------------------------
 step3:在源文件中用ON_COMMAND宏关联消息响应函数
 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,OnHello)
 END_MESSAGE_MAP()
 ------------------------------------------------------------------------------
 step4: 编写消息响应函数
 MainFrm.cpp
 -------------------------------------------------------------------------------
 void CMainFrame::OnHello()
 {
  MessageBox("Hello!");
 }
 --------------------------------------------------------------------------------

13.制作电话本程序
 菜单栏重绘
 CWnd::DarwMenuBar
 MSDN
 ---------------------------------------------------------------------------------------
 CWnd::DrawMenuBar
  Redraws the menu bar.

  void DrawMenuBar( );
 Remarks
  If a menu bar is changed after Windows has created the window, call this function
  to draw the changed menu bar.
 -------------------------------------------------------------------------------------
 窗口重绘
 CWnd::Invalidate
 MSDN
 -----------------------------------------------------------------------------------
 CWnd::Invalidate
  Invalidates the entire client area of CWnd.

  void Invalidate(
     BOOL bErase = TRUE  //表示背景会被擦除
  );
 -------------------------------------------------------------------------------------
 CString::Find
 MSDN
 ------------------------------------------------------------------------------
 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类保存CString对象
 ------------------------------------------------------------------------------------------------
 CWnd::OnCommand
  This method is called by the framework when the user selects an item from a menu, when
  a child control sends a notification message, or when an accelerator keystroke is translated.

  virtual BOOL OnCommand(
  WPARAM wParam,
  LPARAM lParam );
 wParam
  The low-order word of wParam identifies the command ID of the menu item, control, or
  accelerator. The high-order word of wParam specifies the notification message if the
  message is from a control. If the message is from an accelerator, the high-order word
  is 1. If the message is from a menu, the high-order word is 0.
 lParam
  Identifies the control that sends the message if the message is from a control. Otherwise,
  lParam is 0.
 -------------------------------------------------------------------------------------------------
 获取当前视类的指针
 CFrameWnd::GetActiveView
 MSDN
 ------------------------------------------------------------------------------------------------
 CFrameWnd::GetActiveView
  This method obtains a pointer to the active view, if any, attached to a frame window, CFrameWnd.

  CView* GetActiveView( )
  const;
 ---------------------------------------------------------------------------------------------------

Menu2 Project Source Code:
Menu2View.cpp
---------------------------------------------------------------------------------
void CMenu2View::OnChar(UINT nChar, UINT nRepCnt, UINT nFlags)
{
 // TODO: Add your message handler code here and/or call default
 CClientDC dc(this);
 if (0x0d == nChar)
 {
  if (0==++m_nIndex)
  {
   m_menu.CreatePopupMenu();  
   //添加弹出菜单
   GetParent()->GetMenu()->AppendMenu(MF_POPUP,(UINT)m_menu.m_hMenu,"PhoneBook");
   //重画菜单栏,NOTE:菜单是与框架窗口相关,所以需要使用GetParent();
   GetParent()->DrawMenuBar();      
  }
  //添加菜单项
  m_menu.AppendMenu(MF_STRING,IDM_PHONE1+m_nIndex,m_strLine.Left(m_strLine.Find(' ')));
  m_strArray.Add(m_strLine);
  m_strLine.Empty();
  Invalidate();
 }
 else
 {
  m_strLine+=nChar;
  dc.TextOut(0,0,m_strLine);
 
 }
 CView::OnChar(nChar, nRepCnt, nFlags);
}

void CMenu2View::OnPhone1()
{
 // TODO: Add your command handler code here
 CClientDC dc(this);
 dc.TextOut(0,0,m_strArray.GetAt(0));

}

void CMenu2View::OnPhone2()
{
 // TODO: Add your command handler code here
 CClientDC dc(this);
 dc.TextOut(0,0,m_strArray.GetAt(1));

}

void CMenu2View::OnPhone3()
{
 // TODO: Add your command handler code here
 CClientDC dc(this);
 dc.TextOut(0,0,m_strArray.GetAt(2));

}

void CMenu2View::OnPhone4()
{
 // TODO: Add your command handler code here
 CClientDC dc(this);
 dc.TextOut(0,0,m_strArray.GetAt(3));

}
-------------------------------------------------------------------------------------
MainFrm.cpp
--------------------------------------------------------------------------------------
//在框架窗口中截获由视类响应的命令消息,通过覆盖基类的OnCommand函数
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* pMenu2View=(CMenu2View*)GetActiveView();//获得视类的指针
 if (MenuCmdID>=IDM_PHONE1 && MenuCmdID <IDM_PHONE1+pMenu2View->m_strArray.GetSize())
 {
  CClientDC dc(pMenu2View);
  dc.TextOut(0,0,pMenu2View->m_strArray.GetAt(MenuCmdID-IDM_PHONE1));
  //MessageBox("Test");
  return TRUE;
 }

 return CFrameWnd::OnCommand(wParam, lParam);

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值