程序師世界是廣大編程愛好者互助、分享、學習的平台,程序師世界有你更精彩!
首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫知識
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
 程式師世界 >> 編程語言 >> C語言 >> VC >> vc教程 >> 完美實現真彩自繪菜單

完美實現真彩自繪菜單

編輯:vc教程

  一、提出問題

  在VCKBASE上讀到《自繪菜單的實現》[作者:querw]。應用的我自己的正在進行的工程後發現效果不錯,可是有存在許多問題。整個類的設計方面存在很多缺陷(先天,後天的),存在的主要問題如下:

  1. 當應用在多文檔界面(MDI)中的時候,無法對系統自動添加菜單和文檔模板菜單進行自繪(比如無法對文件->最近文件(MRU)菜單項中的文件列表就是系統自動添加)。原因是類內部沒有對CMainFrame::OnInitPopupMenu()消息進行處理的函數, 因此不具備修改系統自動添加菜單項的功能。(BCMENU有這功能,而且工作的不錯)
  2. 作者提到的 BCMENU 不用映射 WM_DRAWITEM 和 WM_MEASUREITEM 兩個消息就能實現自畫功能,實際上是錯誤的。不映射這兩個重要的消息,即使能自繪,也是有問題的,不信看圖。

      菜單編輯器中的模菜單樣

      使用BCMENU並且映射了這兩個消息後的執行情況

      使用BCMENU沒有映射兩個消息的執行情況

      原作者分析的自繪的是因為把主菜單(top-level menu)的子菜單都加載成彈出菜單(popupmenu),是不正確的。真正的原因是因為MFC框架會自動調用CMenu的兩個虛擬函數MeasureItem()和OnDrawItem()。 因此,當CMenuEx派生於CMenu,並且重寫這兩個虛擬函數以後。

    1、MFC框架調用的GetMenu()->MeasureItem()就相當於調用了CMenuEx::MeasureItem(),從而實現自繪菜單控件尺寸的測量。

      2、MFC框架調用GetMenu()->DrawItem()就相當於調用了CMenuEx::DrawItem()來實現自繪菜單控件的自繪操作(不懂??,這正是C++的虛擬的妙用,指向派生類對象的基類指針可以調用派生類的虛擬函數,多麼偉大的發明,誰想出來的???)。與子菜單是否為彈出菜單(popupmenu)沒有什麼關系。以下是摘自WINCORE.CPP的一段程序,也就是WM_MEASUREITEM消息的默認流向的地方,相信大家會從中看出一些端倪。

    void CWnd::OnMeasureItem(int /*nIDCtl*/, LPMEASUREITEMSTRUCT lpMeasureItemStruct)
    {
      if (lpMeasureItemStruct->CtlType == ODT_MENU)
      {
        ......
        // 如果沒有主菜單
        if (pThreadState->m_hTrackingWindow == m_hWnd)
        {
          ......
        }
        else
        {
          // 如果有主菜單
          pMenu = GetMenu(); // 找到窗體的主菜單,注意,pMenu的是CMenu* 類型
        }
        
        // 在當前菜單中尋找ID匹配的菜單項
        pMenu = _AfxFindPopupMenuFromID(pMenu, lpMeasureItemStruct->itemID);
        if (pMenu != NULL)      
          // 如果找到,就調用MeasureItem()
          // 這就是所謂的基類指針指向派生類對象,可以調用派生類虛擬函數的情況了
          pMenu->MeasureItem(lpMeasureItemStruct); 
        else
          TRACE1("Warning: unknown WM_MEASUREITEM for menu item 0x%04X.n",
            lpMeasureItemStruct->itemID);
      }
      else
      {
        ......
      }
      ......
    }    
  3. 當菜單項中含有子菜單(submenu),而不含有分割條的時候,子菜單項的高度不可調。原因為原CMenuEx程序中將分割條的原COMMAND ID(0)改為菜單項的COMMADN ID(-1), 以欺騙MFC框架調用CMenuEx::MeasureItem()來計算子菜單項(submenu)的高度。(很令我失望,這也是促使我自己動手重寫該類的原因之一。不信看程序,看圖)

      摘錄自原CMenuEx.cpp第546-560行

    if(uID == 0) //分隔符
    {
      ::AppendMenu(hNewMenu,MF_SEPARATOR,0,NULL);
      ......
      // 注意,就是下面那個-1,把分割條的ID從0改到-1,
         // 從而是MFC框架誤以為找到了ID為-1的菜單項,並且測量了它的尺寸
      // 而實際上ID為-1的菜單項是不可能被void CWnd::OnMeasureItem()找到的
      ::ModifyMenu(hNewMenu,i,MF_BYPOSITION | MF_OWNERDRAW,-1,(LPCTSTR)pMenuItem);
    }    
    菜單編輯器中沒有分割條菜單的菜單

      原CMenuEx執行的模樣

    本文示例代碼或素材下載

    • 首頁
    • 上一頁
    • 1
    • 2
    • 3
    • 下一頁
    • 尾頁
    • 共3頁
  1. 上一頁:
  2. 下一頁:
Copyright © 程式師世界 All Rights Reserved