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

自繪菜單的實現

編輯:vc教程

  在VCKBASE上讀到《一種漂亮的自繪菜單》 [作者:鄭恆 (lbird)]。應用到我的工程裡後發現:文章中提到的效果能很好的實現。但是有一點不方便:需要映射 WM_DRAWITEM 和 WM_MEASUREITEM 消息才能實現自畫功能。這對於一個基於對話框的工程或者僅僅需要彈出式菜單的工程來說很不方便。網上有一種很有名的自繪菜單 :BCMenu (http://www.rocscience.com/~corkum/BCMenu.html) (在附帶工程中也有 BCMenu),在使用它的時候並不需要映射上述的兩個消息就能實現自繪效果。這個問題讓我覺得很困惑,MSDN也說明:MeasureItem() 和 DrawItem() 兩個虛函數是由框架調用的 。並不用手工映射。可是若不映射上述的兩個消息則顯示不正常。(我查看了好多資料,直到現在還是不明白原因。呵呵:))既然 BCMenu 可以不用映射 WM_DRAWITEM 和 WM_MEASUREITEM 就能實現自畫功能,那麼它肯定經過了特殊處理。果然,BCMenu::LoadMenu()對整個菜單作了處理 。我注意到,如果菜單是彈出式的,那麼不需要映射 WM_DRAWITEM 和 WM_MEASUREITEM 就能實現自畫功能。於是我在CMenuEx::LoadMenu()中重新構建了整個菜單, 把所有的子菜單創建為彈出式的菜單使用API函數::CreatePopupMenu(),代碼如下:

BOOL CMenuEx::LoadMenu(UINT uMenu)
{
  //重新讀入菜單,創建為popup菜單,才能自畫(由框架調用MesureItem() 和 DrawItem()
  HMENU hMenu = ::CreateMenu();
  this->Attach(hMenu);
  //臨時菜單(使用CMenu的LoadMenu()函數讀入菜單,並以之為藍本構建新的菜單)
  CMenu Menu;    
  UINT uID;
  Menu.LoadMenu(uMenu);
  for(int i = 0; i < (int)Menu.GetMenuItemCount(); i++)
  {
    uID = Menu.GetMenuItemID(i);
    if(uID == 0)      //分隔符
    {
      ::AppendMenu(hMenu,MF_SEPARATOR,0,NULL);
    }
    else if((int)uID == -1)    //彈出菜單(即子菜單)
    {
      CMenu *pSubMenu = Menu.GetSubMenu(i);
      
      //創建子菜單  
      HMENU hSubMenu = ::CreatePopupMenu();
      CString strPopup;
      Menu.GetMenuString(i,strPopup,MF_BYPOSITION);
      ::InsertMenu(hMenu,
        i,
        MF_BYPOSITION | MF_POPUP | MF_STRING,
        (UINT)hSubMenu,
        strPopup);            
      
      //對子菜單遞歸調用ChangeMenuStyle(),把子菜單改為MF_OWNERDRAW風格
      ChangeMenuStyle(pSubMenu,hSubMenu);
    }
    else          //正常的菜單項
    {
      CString strText;
      Menu.GetMenuString(uID,strText,MF_BYCOMMAND);
      AppendMenu(MF_STRING,uID,strText);
    }
  }
  Menu.DestroyMenu();      //銷毀臨時菜單
  return TRUE;
}
void CMenuEx::ChangeMenuStyle(CMenu *pMenu,HMENU hNewMenu)
{  
  //關聯為CMenuEx(關聯為CMenuEx後才能自動重畫
  //原因不明(CMenu封裝的結果?)
  CMenuEx *pNewMenu;
  pNewMenu = new CMenuEx;
  pNewMenu->Attach(hNewMenu);
  m_SubMenuArr.Add(pNewMenu);
  UINT uID;
  int nItemCount = pMenu->GetMenuItemCount();
  for(int i = 0; i < nItemCount; i++)
  {
    uID = pMenu->GetMenuItemID(i);
    if(uID == 0)      //分隔符
    {
      ::AppendMenu(hNewMenu,MF_SEPARATOR,0,NULL);
      //pNewMenu->AppendMenu(MF_SEPARATOR,0,NULL);
      CString strText;
      MENUITEM *pMenuItem = new MENUITEM;
      pMenuItem->uID = 0;
      pMenuItem->uIndex = -1;
      pMenuItem->uPositionImageLeft = -1;
      pMenuItem->pImageList = &m_ImageList;
      m_MenuItemArr.Add(pMenuItem);
      
      ::ModifyMenu(hNewMenu,
             i,
             MF_BYPOSITION | MF_OWNERDRAW,
             -1,
             (LPCTSTR)pMenuItem);
    }
    else if(uID == -1)    //彈出菜單(即子菜單)
    {
      CMenu *pSubMenu = pMenu->GetSubMenu(i);
      HMENU hPopMenu = ::CreatePopupMenu();
      CString strPopup;
      pMenu->GetMenuString(i,strPopup,MF_BYPOSITION);
      ::InsertMenu(hNewMenu,
             i,
             MF_BYPOSITION | MF_POPUP,
             (UINT)hPopMenu,
             strPopup);
      MENUITEM *pMenuItem = new MENUITEM;
      pMenuItem->uID = -1;
      pMenuItem->strText = strPopup;
      pMenuItem->uIndex = -1;
      pMenuItem->uPositionImageLeft = -1;
      pMenuItem->pImageList = &m_ImageList;
      m_MenuItemArr.Add(pMenuItem);
      ::ModifyMenu(hNewMenu,
             i,
             MF_BYPOSITION | MF_OWNERDRAW,
             -1,
             (LPCTSTR)pMenuItem);
        
      ChangeMenuStyle(pSubMenu,hPopMenu);
      
    }
    else          //正常的菜單項
    {
      CString strText;
      pMenu->GetMenuString(uID,strText,MF_BYCOMMAND);
      MENUITEM *pMenuItem = new MENUITEM;
      pMenuItem->uID = pMenu->GetMenuItemID(i);
      pMenu->GetMenuString(pMenuItem->uID,
                 pMenuItem->strText,
                 MF_BYCOMMAND);
      pMenuItem->uIndex = -1;
      pMenuItem->uPositionImageLeft = -1;
      pMenuItem->pImageList = &m_ImageList;
      m_MenuItemArr.Add(pMenuItem);
      UINT uState = pMenu->GetMenuState(i,MF_BYPOSITION);
      ::AppendMenu(hNewMenu,
             MF_OWNERDRAW | MF_BYCOMMAND | uState,
             uID,
             (LPCTSTR)pMenuItem);
    }
  }
}   

  這樣,利用標注的CMenu::LoadMenu()函數讀入菜單,並根據這個菜單重新構建一個新的菜單,在新菜單中把所有的子菜單創建為彈出式菜單並關聯一個CMenuEx類。根據需要,我提供了一個

本文示例代碼或素材下載

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