為了實現菜單的自繪,花了我幾個小時,其實真正解決後又發現很簡單。實現菜單的自繪只需要三個步驟:
第一步:將所有功能表項目設定為MF_OWNERDRAW,即自繪模式
第二步:在WM_MEASUREITEM訊息中設定功能表項目的大小
第三步:在WM_DRAWITEM訊息中進行功能表項目的繪製
問題首先出現在了第一步,我要繪製的是一個操作功能表,即右鍵菜單,要將功能表項目設定為MF_OWNERDRAW,需要用到ModifyMenu函數,起始由於ModifyMenu函數的參數設定錯誤,導致程式怎麼也響應不了WM_MEASUREITEM和WM_DRAWITEM訊息,所以建議在使用ModifyMenu時對傳回值進行檢查。
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訊息中根據功能表項目的大小來進行重繪。
到第三步也遇到了幾個問題,由於最初對WM_DRAWITEM訊息中的LPDRAWITEMSTRUCT結構體不瞭解,以致寫出的程式不管在什麼時候都會作同一個繪製操作,先來看看WM_DRAWITEM訊息的聲明:
afx_msg void CMainWindow::OnDrawItem(int nIDCtl, LPDRAWITEMSTRUCT lpdis);
在這個訊息中有兩個參數,在自繪菜單時,兩個參數都要用到。其中nIDCtl,書上說是所屬控制項的ID,不太明白是什麼意思,在MSDN看到,對於菜單發出的WM_DRAWITEM訊息,nIDCtl為0。再說LPDRAWITEMSTRUCT結構體,該結構體中包含了菜單複選狀態、選中狀態以及功能表項目的大小等資訊。
下面是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