MFC中實現自繪菜單

爲了實現菜單的自繪,花了我幾個小時,其實真正解決後又發現很簡單。實現菜單的自繪只須要三個步驟:函數

第一步:將全部菜單項設置爲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

相關文章
相關標籤/搜索