c++ - 如何在所有者绘制的 MFC CMenu 派生菜单中显示复选框?

标签 c++ visual-c++ mfc ownerdrawn cmenu

我有一个继承自 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?

我希望复选框出现,但它没有出现。 首先,我尝试使用来自 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

那没有成功。然后我尝试根据 a page on MSDN about the MENUITEMINFO struct 使用对 SetMenuItemInfo 的调用来设置 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));

...,这将导致使用指向 menuProperties 的 lpDrawItemStruct->itemData 调用 DrawItem:效果很好。

在我的自绘菜单中仍然没有复选框。我错过了什么?如何给自绘的 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 MARGIN


ReleaseDC( NULL, dc.Detach() );

关于c++ - 如何在所有者绘制的 MFC CMenu 派生菜单中显示复选框?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/45285082/

相关文章:

c++ - 是否可以为不应编译的表达式表达 static_assert?

c++ - 托管代码中使用的 STL vector

c++ - 64位MFC版本访问冲突异常

c++ - 如何加快MFC中旋转文本的输出

C++扩展类强制某些方法私有(private)

c++ - Visual Studio 2008 下的虚假 C++ 析构函数调用(在 GCC 下不存在)

c++ - PEM 转换 (PKCS7) 到 DER - 又名 Base64 C++ 问题

windows - vcvars64.bat 文件丢失

visual-c++ - CException::`RTTI 完整对象定位器在 VC++ 应用程序中

c# - 无法将 winform 控件大小传递给非托管代码