爲了實現菜單的自繪,花了我幾個小時,其實真正解決後又發現很簡單。實現菜單的自繪只須要三個步驟:函數
第一步:將全部菜單項設置爲MF_OWNERDRAW,即自繪模式this
第二步:在WM_MEASUREITEM消息中設置菜單項的大小code
第三步:在WM_DRAWITEM消息中進行菜單項的繪製it
問題首先出如今了第一步,我要繪製的是一個上下文菜單,即右鍵菜單,要將菜單項設置爲MF_OWNERDRAW,須要用到ModifyMenu函數,起始因爲ModifyMenu函數的參數設置錯誤,致使程序怎麼也響應不了WM_MEASUREITEM和WM_DRAWITEM消息,因此建議在使用ModifyMenu時對返回值進行檢查。class
void CMainWindow::OnRButtonDown(UINT nFlags, CPoint point) { ClientToScreen(&point); CMenu Menu; Menu.LoadMenuW(IDR_MENU2); CMenu *pMenu = Menu.GetSubMenu(0); CString strText; for (int i = 0; i < pMenu->GetMenuItemCount(); i++) { BOOL bModi = pMenu->ModifyMenuW(ID_123_456 + i, MF_BYCOMMAND|MF_OWNERDRAW, ID_123_456 + i); if (!bModi) { TRACK("ModifyMenu fail!"); } pMenu->GetMenuStringW(i, strText, MF_BYPOSITION); } pMenu->TrackPopupMenu(TPM_LEFTBUTTON|TPM_LEFTALIGN, point.x, point.y, this); }
第一步的問題解決後,接在在第二步的WM_MEASUREITEM消息中設置菜單項的大小:程序
void CMainWindow::OnMeasureItem(int nIDCtl, LPMEASUREITEMSTRUCT lpmis) { //lpmis->itemWidth = ::GetSystemMetrics(SM_CYMENU) * 4; lpmis->itemWidth = 150; lpmis->itemHeight = ::GetSystemMetrics(SM_CYMENU); }
在WM_MEASUREITEM消息中設置的菜單項大小會傳入WM_DRAWITEM消息中,而後再在WM_DRAWITEM消息中根據菜單項的大小來進行重繪。im
到第三步也遇到了幾個問題,因爲最初對WM_DRAWITEM消息中的LPDRAWITEMSTRUCT結構體不瞭解,以至寫出的程序無論在何時都會做同一個繪製操做,先來看看WM_DRAWITEM消息的聲明:top
afx_msg void CMainWindow::OnDrawItem(int nIDCtl, LPDRAWITEMSTRUCT lpdis);img
在這個消息中有兩個參數,在自繪菜單時,兩個參數都要用到。其中nIDCtl,書上說是所屬控件的ID,不太明白是什麼意思,在MSDN看到,對於菜單發出的WM_DRAWITEM消息,nIDCtl爲0。再說LPDRAWITEMSTRUCT結構體,該結構體中包含了菜單複選狀態、選中狀態以及菜單項的大小等信息。di
下面是OnDrawItem消息的實現代碼:
void CMainWindow::OnDrawItem(int nIDCtl, LPDRAWITEMSTRUCT lpdis) { CBrush *brush = new CBrush; CPen *pen = new CPen; CString strText; CDC *pDC = CDC::FromHandle(lpdis->hDC); //獲取菜單項的設備句柄 //菜單項是否爲選中狀態 if ((lpdis->itemState & ODS_SELECTED)) { //在菜單項上自繪矩形框的背景顏色 brush->CreateSolidBrush(RGB(182, 189,210)); //在菜單項自繪矩形的邊框顏色 pen->CreatePen(PS_SOLID, 1, RGB(10,36,106)); //設置菜單項的文字背景顏色 pDC->SetBkColor(RGB(182,189,210)); } else { brush->CreateSolidBrush(GetSysColor(COLOR_MENU)); pen->CreatePen(PS_SOLID, 0, GetSysColor(COLOR_MENU)); pDC->SetBkColor(GetSysColor(COLOR_MENU)); } pDC->SelectObject(pen); pDC->SelectObject(brush); //在當前菜單項上畫一個矩形框 pDC->Rectangle(lpdis->rcItem.left, lpdis->rcItem.top, lpdis->rcItem.right, lpdis->rcItem.bottom); /*--------------------------------------*/ //獲取當前消息所在菜單項的文本 CMenu menu; menu.Attach((HMENU)lpdis->hwndItem); menu.GetMenuStringW(lpdis->itemID, strText,MF_BYCOMMAND); /*--------------------------------------*/ //若是爲菜單發出的DrawItem消息 if (nIDCtl == 0) { //在菜單項上輸出菜單文本 pDC->TextOutW(lpdis->rcItem.left + 20, lpdis->rcItem.top + 4, strText.GetBuffer(0), strText.GetLength()); } menu.Detach(); delete brush; delete pen; }
效果圖:
參考資料:http://www.vckbase.com/document/viewdoc/?id=1583