2017-07-24 68 views
1

我有一個繼承自MFC CMenu類的菜單類:MyMenu : public CMenu。 MyMenu從資源文件中加載,並且改爲自繪菜單(使用CodeGuru的代碼示例,這適用於菜單項的樣式)。現在我想激活菜單項左邊的複選框。如何顯示所有者繪製的MFC CMenu派生菜單中的複選框?

MyMenu menu; 
menu.LoadMenu(IDR_MYCONTEXT_MENU); 
MyMenu* subm = ef_cast<MyMenu*>(menu.GetSubMenu(0)); 
if (subm == nullptr) return; 

subm->ChangeToOwnerDraw(*subm); 

subm->CheckMenuItem(ID_COPY_ITEM, m_ItemCopied ? MF_CHECKED : MF_UNCHECKED); 
subm->CheckMenuItem(ID_COPY_ITEM, MF_CHECKED); //Force visibility? 

我希望複選框出現,但它沒有。 首先,我想從MSDN設置使用的代碼示例的複選框位圖與SetMenuItemBitmaps(...):

int commandID = ID_COPY_ITEM; 
CBitmap checkedBitmap; 
checkedBitmap.Attach(MyMenu::GetMyCheckBitmaps(CHECK)); 

CBitmap uncheckedBitmap; 
uncheckedBitmap.Attach(MyMenu::GetMyCheckBitmaps(UNCHECK)); 

SetMenuItemBitmaps(*subm, commandID, MF_BYCOMMAND, uncheckedBitmap, checkedBitmap); 
subm->SetMenuItemBitmaps(commandID, MF_BYCOMMAND, &uncheckedBitmap, &checkedBitmap); //Same as previous line 

那沒有發揮出來。然後我試圖使用到SetMenuItemInfo呼叫,基於a page on MSDN about the MENUITEMINFO struct設置MENUITEMINFO:

MENUITEMINFO mItemInfo{}; 
mItemInfo.cbSize = sizeof(MENUITEMINFO); 

mItemInfo.fMask |= MIIM_CHECKMARKS | MIIM_STATE; 
mItemInfo.fState |= MFS_CHECKED | MFS_DEFAULT; 
mItemInfo.hbmpChecked = MyMenu::GetMyCheckBitmaps(CHECK); 
mItemInfo.hbmpUnchecked = MyMenu::GetMyCheckBitmaps(UNCHECK); 
subm->SetMenuItemInfo(commandID, &mItemInfo, FALSE); 

最後,可以肯定的是,菜單項實際上是可以改變的,我添加了一行

subm->ModifyMenu(ID_COPY_ITEM, MF_BYCOMMAND, ID_COPY_ITEM, reinterpret_cast<LPCTSTR>(&menuProperties)); 

...,這將導致DrawItem被調用lpDrawItemStruct-> itemData指向menuProperties:這很好。

在我的所有者繪製菜單中仍然沒有複選框。我錯過了什麼?如何添加一個複選框到所有者繪製的MFC PopupMenu?

+0

不要忘記給你的MeasureItem一點餘量可檢查菜單項? 你正在使用什麼版本的VS? 6.0? 如果2008帶有功能包或更高版本,請查看CMFCPopupMenu。 – JohnCz

+0

我正在使用VS2015的舊代碼庫。我會看看CMFCPopupMenu。 –

回答

0

如果你的菜單是老闆抽獎,你應該做你的DrawItem方法類似

LOGFONT lf; 

// if font defined by you 
if(i_have a_font) 
{ 
    lf= your_log_font; 
} 
else 
{ 
    NONCLIENTMETRICS ncm; 
    ncm.cbSize= sizeof(ncm); 
    SystemParametersInfo(SPI_GETNONCLIENTMETRICS, sizeof(ncm), &ncm, 0); 

    lf= ncm.lfMenuFont; 
} 

CSize sizeImage = CSize(abs(lf.lfHeight), abs(lf.lfHeight)) 

if ((lpDrawItemStruct->itemState & ODS_CHECKED)) 
{ 
    CRect rectImage= CRect(lpDrawItemStruct->rcItem); 
    CPoint ptImage(0, 
     rectImage.top +(rectImage.Height() - sizeImage.cy)/2 +((rectImage.Height() - sizeImage.cy) % 2)); 

    //TODO! Need to fix; currently drawing checks on situations it should draw radios! 
    CMenuImages::SetColor(CMenuImages::ImageBlack, clrText); 
    MENUITEMINFO mii; 
    ZeroMemory(&mii, sizeof (mii)); 
    mii.cbSize= sizeof(mii); 
    mii.fMask= MIIM_TYPE; 

    ::GetMenuItemInfo(this->m_hMenu, lpDrawItemStruct->itemID, MF_BYCOMMAND, &mii); 

    if(mii.fType & MFT_RADIOCHECK) 
     CMenuImages::Draw(pDC,CMenuImages::IdRadio, ptImage, CMenuImages::ImageBlack, sizeImage); 
    else 
     CMenuImages::Draw(pDC,CMenuImages::IdCheck, ptImage, CMenuImages::ImageBlack, sizeImage); 
} 

pDC->ReleaseOutputDC(); 

。你爲什麼要使用所有者繪製菜單

CDC dc; 
dc.Attach(GetDC(NULL)); 

CSize size; 

LOGFONT lf; 

// if font defined by you 
if(i_have a_font) 
{ 
    lf= your_log_font; 
} 
else 
{ 
    NONCLIENTMETRICS ncm; 
    ncm.cbSize= sizeof(ncm); 
    SystemParametersInfo(SPI_GETNONCLIENTMETRICS, sizeof(ncm), &ncm, 0); 

    lf= ncm.lfMenuFont; 
} 

CFont font; 
VERIFY(font.CreateFontIndirect(&lf)); 
CFont* pOldFont= dc.SelectObject(&font); 


// text is a CString containing the text of your menu. I made it enter into the function by passing it through the field `itemData` of the parameter `LPMEASUREITEMSTRUCT lpMeasureItemStruct` 

CSize size= dc.GetTextExtent(text); 
dc.SelectObject(&pOldFont); 

// CHOOSE WHAT BEST FITS YOU 
    size.cx+= (2 * abs(lf.lfHeight)); // Margin for Check Mark at Left and Margin for Popup Arrow at Right 
// OR 
    size.cx+= (2* SM_CXMENUCHECK); // Margin for Check Mark at Left and Margin for Popup Arrow at Right 

lpMeasureItemStruct->itemWidth= size.cx; <= HERE IS THE LINE ASSIGNING THE NEW WIDTH INCLUDING THE MARGIN 


ReleaseDC(NULL, dc.Detach()); 
相關問題