note : append menu to menu on right click menu

来源:互联网 发布:知乎首页代码 编辑:程序博客网 时间:2024/05/22 01:36

今天想实现一个右键菜单出现时,出现的总菜单 = 公用菜单(编辑类的功能) + 具体菜单每个View一个特定菜单)

从CodeProject上找了一个函数MergeMenu, 搞定.

bool MergeMenu( CMenu * pMenuDestination,                    const CMenu * pMenuAdd,                    bool bTopLevel);
效果图:



附件菜单到菜单的实现

基类View

#pragma once// CViewNormal viewclass CViewNormal : public CView{    DECLARE_DYNCREATE(CViewNormal)protected:    CViewNormal();    virtual ~CViewNormal();public:    virtual void OnDraw(CDC* pDC);    void SetName(wchar_t * pName);    /// 在pMenuOrg基础上,加上功能菜单    virtual void AppendFunctionMenu(CMenu * pMenuOrg);    /// 在pMenuOrg上附加"菜单资源ID"为 nMenuIDRc 的子菜单    /// 只有子类知道具体要附加什么子菜单    /// 子类实现虚函数 AppendFunctionMenu    /// 调用AppendFunctionMenuID, 附加自己的子菜单    void AppendFunctionMenuID(CMenu * pMenuOrg, UINT nMenuIDRc);    bool MergeMenu( CMenu * pMenuDestination,                    const CMenu * pMenuAdd,                    bool bTopLevel);    /// 显示区重置    void fnDispAreaReset();protected:    void WriteToRichEditCtrl(const wchar_t * szMsg);#ifdef _DEBUG    virtual void AssertValid() const;#ifndef _WIN32_WCE    virtual void Dump(CDumpContext& dc) const;#endif  // #ifndef _WIN32_WCE#endif  // #ifdef _DEBUGprotected:    DECLARE_MESSAGE_MAP()public:    virtual void OnInitialUpdate();    virtual void DoDataExchange(CDataExchange* pDX);    virtual BOOL OnCmdMsg(UINT nID, int nCode, void* pExtra, AFX_CMDHANDLERINFO* pHandlerInfo);    virtual BOOL OnNotify(WPARAM wParam, LPARAM lParam, LRESULT* pResult);    afx_msg void OnDestroy();    afx_msg int OnCreate(LPCREATESTRUCT lpCreateStruct);    LRESULT OnEditCut(WPARAM wparam, LPARAM lparam);    LRESULT OnEditCopy(WPARAM wparam, LPARAM lparam);    LRESULT OnEditPaste(WPARAM wparam, LPARAM lparam);    LRESULT OnEditSelectAll(WPARAM wparam, LPARAM lparam);    LRESULT OnEditDispAreaReset(WPARAM wparam, LPARAM lparam);private:    CString         m_strName;    CRichEditCtrl   m_RichEdit;};

// ViewNormal.cpp : implementation file//#include "stdafx.h"#include "MainFrm.h"#include <afxpriv.h>#include <stdio.h>#include "srcR3.h"#include "ViewNormal.h"#include "string/stringHelper.h"// CViewNormalIMPLEMENT_DYNCREATE(CViewNormal, CView)CViewNormal::CViewNormal(){    m_strName = L"";}CViewNormal::~CViewNormal(){}/// @attention ON_MESSAGE 才能响应控件的右键菜单!BEGIN_MESSAGE_MAP(CViewNormal, CView)    ON_WM_CREATE()    ON_WM_DESTROY()    ON_MESSAGE(ID_EDIT_CUT_ON_EDIT_CTRL, OnEditCut)    ON_MESSAGE(ID_EDIT_COPY_ON_EDIT_CTRL, OnEditCopy)    ON_MESSAGE(ID_EDIT_PASTE_ON_EDIT_CTRL, OnEditPaste)    ON_MESSAGE(ID_EDIT_SEL_ALL_ON_EDIT_CTRL, OnEditSelectAll)    ON_MESSAGE(ID_EDIT_DISP_AREA_RESET_ON_EDIT_CTRL, OnEditDispAreaReset)END_MESSAGE_MAP()void CViewNormal::DoDataExchange(CDataExchange* pDX){    CView::DoDataExchange(pDX);}// CViewNormal drawingvoid CViewNormal::OnDraw(CDC* pDC){    CDocument* pDoc = GetDocument();    pDC->TextOutW(10, 10, m_strName);}// CViewNormal diagnostics#ifdef _DEBUGvoid CViewNormal::AssertValid() const{CView::AssertValid();}#ifndef _WIN32_WCEvoid CViewNormal::Dump(CDumpContext& dc) const{CView::Dump(dc);}#endif#endif //_DEBUGvoid CViewNormal::SetName(wchar_t * pName){    m_strName = (NULL != pName) ? pName : L"I have not name";}void CViewNormal::AppendFunctionMenu(CMenu * pMenuOrg){    TRACE(L">> CViewNormal::AppendFunctionMenu");}// CViewNormal message handlersint CViewNormal::OnCreate(LPCREATESTRUCT lpCreateStruct){    DWORD   dwStyle =   0;    if (CView::OnCreate(lpCreateStruct) == -1)        return -1;        dwStyle = WS_CHILD | WS_VISIBLE | ES_AUTOVSCROLL | ES_AUTOHSCROLL |        ES_AUTOHSCROLL | ES_MULTILINE | WS_HSCROLL | WS_VSCROLL;    if (!m_RichEdit.Create( dwStyle,                            CRect(0,0,0,0),                            this,                            AFX_IDW_PANE_FIRST))    {        TRACE0("Failed to create RichEdit window\n");        return -1;    }    /// 将鼠标消息送给父窗口    /// @note 不设置这个, 进不了CRichEditCtrl控件父窗口的OnNotify    m_RichEdit.SetEventMask(ENM_MOUSEEVENTS);    /// 设置选择范围为不选择内容    m_RichEdit.SetSel(0,0);    return 0;}void CViewNormal::OnInitialUpdate(){    CRect rt;    CString strMsg;    CView::OnInitialUpdate();    /// 将控件铺满View客户区    /// 如果要在这个view中放置别的控件, 请不要铺满, 自己来摆放控件位置    GetClientRect(&rt);    m_RichEdit.MoveWindow(rt);    fnDispAreaReset();}void CViewNormal::OnDestroy(){    m_RichEdit.DestroyWindow();    CView::OnDestroy();}BOOL CViewNormal::OnCmdMsg(UINT nID, int nCode, void* pExtra, AFX_CMDHANDLERINFO* pHandlerInfo){    return CView::OnCmdMsg(nID, nCode, pExtra, pHandlerInfo);}LRESULT CViewNormal::OnEditCut(WPARAM wparam, LPARAM lparam){    TRACE(L">> CViewNormal::OnEditCut\r\n");    m_RichEdit.Cut();    return 0;}LRESULT CViewNormal::OnEditCopy(WPARAM wparam, LPARAM lparam){    TRACE(L">> CViewNormal::OnEditCopy\r\n");    m_RichEdit.Copy();    return 0;}LRESULT CViewNormal::OnEditPaste(WPARAM wparam, LPARAM lparam){    TRACE(L">> CViewNormal::OnEditPaste\r\n");    m_RichEdit.Paste();    return 0;}LRESULT CViewNormal::OnEditSelectAll(WPARAM wparam, LPARAM lparam){    TRACE(L">> CViewNormal::OnEditSelectAll\r\n");    m_RichEdit.SetSel(0, -1);    return 0;}LRESULT CViewNormal::OnEditDispAreaReset(WPARAM wparam, LPARAM lparam){    fnDispAreaReset();    return 0;}void CViewNormal::WriteToRichEditCtrl(const wchar_t * szMsg){    int nOldLines   =   0;    int nNewLines   =   0;    int nScroll     =   0;    long nInsertionPoint    =   0;    CHARFORMAT  cf;    nOldLines = m_RichEdit.GetLineCount();    cf.cbSize = sizeof(CHARFORMAT);    cf.dwMask = CFM_COLOR;    cf.dwEffects = 0; ///< To disable CFE_AUTOCOLOR    cf.crTextColor = RGB(128, 128, 128);    m_RichEdit.SetSelectionCharFormat(cf);    nInsertionPoint = m_RichEdit.GetWindowTextLength();    m_RichEdit.SetSel(nInsertionPoint, -1);    m_RichEdit.ReplaceSel(szMsg);    nNewLines = m_RichEdit.GetLineCount();    nScroll = nNewLines - nOldLines;    m_RichEdit.LineScroll(nScroll);}void CViewNormal::fnDispAreaReset(){    std::wstring    strMsg;    TRACE(L">> CViewNormal::OnEditDispAreaReset\r\n");    m_RichEdit.SetSel(0, -1);    m_RichEdit.Cut();    strMsg = StringFormatV(        L"[%s]\r\n"        L"%s\r\n",         m_strName,         COleDateTime::GetCurrentTime().Format(L"%y-%m-%d %H:%M:%S"));    WriteToRichEditCtrl(strMsg.c_str());}BOOL CViewNormal::OnNotify(WPARAM wParam, LPARAM lParam, LRESULT* pResult){    BOOL            bRc         =   TRUE;      CString         csMsg;    UINT            uMessage    =   0;    MSGFILTER *     lpMsgFilter =   (MSGFILTER *)lParam;     CPoint          point;    CMenu           menu;    CMenu *         pMenuPopup  =   NULL;    CMainFrame *    pMainFrame  =   NULL;    HWND            hWndObj     =   NULL;    if ((AFX_IDW_PANE_FIRST == wParam)         && (EN_MSGFILTER == lpMsgFilter->nmhdr.code)        && (WM_RBUTTONDOWN == lpMsgFilter->msg))    {        /// View中的RichEdit, 右键按下, 准备弹出菜单        ::GetCursorPos(&point);        menu.LoadMenu(IDR_MENU_RIGHT_CLICK);    ///< 公用菜单        pMenuPopup = menu.GetSubMenu(0);        ASSERT(NULL != pMenuPopup);        /// 附加每个View特有的功能菜单        /// 虚函数, 由子类实现        AppendFunctionMenu(pMenuPopup);        uMessage = pMenuPopup->TrackPopupMenu(            TPM_LEFTALIGN | TPM_LEFTBUTTON | TPM_NONOTIFY | TPM_RETURNCMD,            point.x,            point.y,             this);        pMenuPopup->DestroyMenu();         bRc = PostMessage(uMessage, 0, 0);        TRACE(L"<< %s = PostMessage(0x%X, 0, 0)\r\n",            bRc ? L"TRUE" : L"FALSE",            uMessage);    }    return CView::OnNotify(wParam, lParam, pResult);}void CViewNormal::AppendFunctionMenuID(CMenu * pMenuOrg, UINT nMenuIDRc){    CMenu       menuToBeAdd;    CMenu *     pMenuToBeAdd  =   NULL;    menuToBeAdd.LoadMenu(nMenuIDRc);    pMenuToBeAdd = menuToBeAdd.GetSubMenu(0);    ASSERT(NULL != pMenuToBeAdd);    MergeMenu(pMenuOrg, pMenuToBeAdd, false);    pMenuToBeAdd->DestroyMenu();}bool CViewNormal::MergeMenu(CMenu * pMenuDestination,    const CMenu * pMenuAdd,    bool bTopLevel){    // MergeMenu original url from :     // http://www.codeproject.com/Articles/1577/Merging-Two-Menus#    // Abstract:    //      Merges two menus.    //    // Parameters:    //      pMenuDestination    - [in, retval] destination menu handle    //      pMenuAdd            - [in] menu to merge    //      bTopLevel           - [in] indicator for special top level behavior    //    // Return value:    //      <false> in case of error.    //    // Comments:    //      This function calles itself recursivley. If bTopLevel is set to true,    //      we append popups at top level or we insert before <Window> or <Help>.    // get the number menu items in the menus    int iMenuAddItemCount = pMenuAdd->GetMenuItemCount();    int iMenuDestItemCount = pMenuDestination->GetMenuItemCount();    // if there are no items return    if( iMenuAddItemCount == 0 )        return true;    // if we are not at top level and the destination menu is not empty    // -> we append a seperator    if( !bTopLevel && iMenuDestItemCount > 0 )        pMenuDestination->AppendMenu(MF_SEPARATOR);    // iterate through the top level of <pMenuAdd>    for( int iLoop = 0; iLoop < iMenuAddItemCount; iLoop++ )    {        // get the menu string from the add menu        CString sMenuAddString;        pMenuAdd->GetMenuString( iLoop, sMenuAddString, MF_BYPOSITION );        // try to get the submenu of the current menu item        CMenu* pSubMenu = pMenuAdd->GetSubMenu(iLoop);        // check if we have a sub menu        if (!pSubMenu)        {            // normal menu item            // read the source and append at the destination            UINT nState = pMenuAdd->GetMenuState( iLoop, MF_BYPOSITION );            UINT nItemID = pMenuAdd->GetMenuItemID( iLoop );            if( pMenuDestination->AppendMenu( nState, nItemID, sMenuAddString ))            {                // menu item added, don't forget to correct the item count                iMenuDestItemCount++;            }            else            {                TRACE( "MergeMenu: AppendMenu failed!\n" );                return false;            }        }        else        {            // create or insert a new popup menu item            // default insert pos is like ap            int iInsertPosDefault = -1;            // if we are at top level merge into existing popups rather than            // creating new ones            if( bTopLevel )            {                ASSERT( sMenuAddString != "&?" && sMenuAddString != "?" );                CString sAdd( sMenuAddString );                sAdd.Remove('&');  // for comparison of menu items supress '&'                bool bAdded = false;                // try to find existing popup                for( int iLoop1 = 0; iLoop1 < iMenuDestItemCount; iLoop1++ )                {                    // get the menu string from the destination menu                    CString sDest;                    pMenuDestination->GetMenuString( iLoop1, sDest, MF_BYPOSITION );                    sDest.Remove( '&' ); // for a better compare (s.a.)                    if( sAdd == sDest )                    {                        // we got a hit -> merge the two popups                        // try to get the submenu of the desired destination menu item                        CMenu* pSubMenuDest = pMenuDestination->GetSubMenu( iLoop1 );                        if( pSubMenuDest )                        {                            // merge the popup recursivly and continue with outer for loop                            if( !MergeMenu( pSubMenuDest, pSubMenu, false))                                return false;                            bAdded = true;                            break;                        }                    }                    // alternativ insert before <Window> or <Help>                    if( iInsertPosDefault == -1 && ( sDest == "Window" || sDest == "?" || sDest == "Help" ))                        iInsertPosDefault = iLoop1;                }                if( bAdded )                {                    // menu added, so go on with loop over pMenuAdd's top level                    continue;                }            }            // if the top level search did not find a position append the menu            if( iInsertPosDefault == -1 )                iInsertPosDefault = pMenuDestination->GetMenuItemCount();            // create a new popup and insert before <Window> or <Help>            CMenu NewPopupMenu;            if( !NewPopupMenu.CreatePopupMenu() )            {                TRACE( "MergeMenu: CreatePopupMenu failed!\n" );                return false;            }            // merge the new popup recursivly            if( !MergeMenu( &NewPopupMenu, pSubMenu, false))                return false;            // insert the new popup menu into the destination menu            HMENU hNewMenu = NewPopupMenu.GetSafeHmenu();            if( pMenuDestination->InsertMenu( iInsertPosDefault,                MF_BYPOSITION | MF_POPUP | MF_ENABLED,                 (UINT)hNewMenu, sMenuAddString ))            {                // don't forget to correct the item count                iMenuDestItemCount++;            }            else            {                TRACE( "MergeMenu: InsertMenu failed!\n" );                return false;            }            // don't destroy the new menu                   NewPopupMenu.Detach();        }     }     return true;}

子类View

#pragma once#include "ViewNormal.h"// CViewDrvManager viewclass CViewDrvManager : public CViewNormal{DECLARE_DYNCREATE(CViewDrvManager)protected:CViewDrvManager();           // protected constructor used by dynamic creationvirtual ~CViewDrvManager();    virtual void AppendFunctionMenu(CMenu * pMenuOrg);public:virtual void OnDraw(CDC* pDC);      // overridden to draw this view#ifdef _DEBUGvirtual void AssertValid() const;#ifndef _WIN32_WCEvirtual void Dump(CDumpContext& dc) const;#endif#endifprotected:DECLARE_MESSAGE_MAP()public:    LRESULT OnViewLsMiniFilterInstall(WPARAM wparam, LPARAM lparam);    LRESULT OnViewLsMiniFilterRun(WPARAM wparam, LPARAM lparam);    LRESULT OnViewLsMiniFilterStop(WPARAM wparam, LPARAM lparam);    LRESULT OnViewLsMiniFilterUnInstall(WPARAM wparam, LPARAM lparam);};

// ViewDrvManager.cpp : implementation file//#include "stdafx.h"#include "srcR3.h"#include "ViewDrvManager.h"#include "TreeViewNormal.h"// CViewDrvManagerIMPLEMENT_DYNCREATE(CViewDrvManager, CViewNormal)CViewDrvManager::CViewDrvManager(){}CViewDrvManager::~CViewDrvManager(){}BEGIN_MESSAGE_MAP(CViewDrvManager, CViewNormal)    ON_MESSAGE(ID_IDR_LSMINIFILTER_INSTALL, OnViewLsMiniFilterInstall)    ON_MESSAGE(ID_IDR_LSMINIFILTER_RUN, OnViewLsMiniFilterRun)    ON_MESSAGE(ID_IDR_LSMINIFILTER_STOP, OnViewLsMiniFilterStop)    ON_MESSAGE(ID_IDR_LSMINIFILTER_UNINSTALL, OnViewLsMiniFilterUnInstall)END_MESSAGE_MAP()// CViewDrvManager drawingvoid CViewDrvManager::OnDraw(CDC* pDC){CDocument* pDoc = GetDocument();// TODO: add draw code here}// CViewDrvManager diagnostics#ifdef _DEBUGvoid CViewDrvManager::AssertValid() const{CView::AssertValid();}#ifndef _WIN32_WCEvoid CViewDrvManager::Dump(CDumpContext& dc) const{CView::Dump(dc);}#endif#endif //_DEBUG// CViewDrvManager message handlersvoid CViewDrvManager::AppendFunctionMenu(CMenu * pMenuOrg){    AppendFunctionMenuID(pMenuOrg, IDR_MENU_DRV_MANAGER);}LRESULT CViewDrvManager::OnViewLsMiniFilterInstall(WPARAM wparam, LPARAM lparam){    WriteToRichEditCtrl(L"CViewDrvManager::OnViewLsMiniFilterInstall\r\n");    return 0;}LRESULT CViewDrvManager::OnViewLsMiniFilterRun(WPARAM wparam, LPARAM lparam){    WriteToRichEditCtrl(L"CViewDrvManager::OnViewLsMiniFilterRun\r\n");    return 0;}LRESULT CViewDrvManager::OnViewLsMiniFilterStop(WPARAM wparam, LPARAM lparam){    WriteToRichEditCtrl(L"CViewDrvManager::OnViewLsMiniFilterStop\r\n");    return 0;}LRESULT CViewDrvManager::OnViewLsMiniFilterUnInstall(WPARAM wparam, LPARAM lparam){    WriteToRichEditCtrl(L"CViewDrvManager::OnViewLsMiniFilterUnInstall\r\n");    return 0;}




原创粉丝点击