У меня есть класс меню, который наследует от класса MFC CMenu: MyMenu : public CMenu
,
MyMenu загружается из файла ресурсов и затем изменяется на меню, нарисованное владельцем (используя пример кода из CodeGuru, который хорошо работает для оформления пунктов меню). Теперь я хочу активировать флажок слева от пункта меню.
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?
Я ожидал, что флажок появится, но это не так.
Сначала я попытался установить растровые изображения флажка с помощью SetMenuItemBitmaps (…), используя пример кода из MSDN:
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
Это не сработало. Затем я попытался установить MENUITEMINFO, используя вызов SetMenuItemInfo, основанный на страница в MSDN о структуре 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?
Если ваше меню нарисовано владельцем, вы должны сделать что-то вроде
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();
на ваше DrawItem
метод.
Не забудьте дать небольшой запас MeasureItem
для проверяемых пунктов меню:
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 MARGINReleaseDC( NULL, dc.Detach() );
Других решений пока нет …