带有大图像和复选框的功能区按钮项目

时间:2014-03-10 13:55:29

标签: mfc mfc-feature-pack

我有一个菜单附加到这样的分割功能区按钮(VS2008,Feature Pack):

std::auto_ptr<CMFCRibbonButton> apBtn3(new CMFCRibbonButton(ID_RIBBON_BTN_3, _T("Split Button"), 2, 2));
apBtn3->SetMenu(IDR_RIBBON_MENU_1, TRUE);
apBtn3->SetAlwaysLargeImage();
apBtn3->RemoveSubItem(0);
std::auto_ptr<CMFCRibbonButton> apSubButton(new CMFCRibbonButton(ID_RIBBON_MBTN_1, _T("Item 1"), 2, 2));   
apSubButton->SetAlwaysLargeImage();
apBtn3->AddSubItem(apSubButton.release(), 0);
pPanel1->Add(apBtn3.release());

我想在每个菜单项前添加复选框,并在SetCheck()处理程序中提供CN_UPDATE_COMMAND_UI次调用,但只有在我禁用大图标时,复选框才会显示。

有没有办法在CMFCRibbonButton菜单中使用复选框和大图标?如果没有,那么最好的解决方法是什么?

2 个答案:

答案 0 :(得分:0)

我找到了一个可用的解决方法,通过alpha混合绿色圆圈检查大图标,并在图标上添加一个复选标记 - Windows用于在控制面板中标记默认音频设备或打印机的相同解决方案:

screenshot

这是我的CMFCRibbonButtonEx类声明:

class CMFCRibbonButtonEx : public CMFCRibbonButton
{
// Construction
public:
    CMFCRibbonButtonEx();
    CMFCRibbonButtonEx(UINT nID, LPCTSTR lpszText, int nSmallImageIndex = -1, int nLargeImageIndex = -1, BOOL bAlwaysShowDescription = FALSE);
    CMFCRibbonButtonEx(UINT nID, LPCTSTR lpszText, HICON hIcon, BOOL bAlwaysShowDescription = FALSE, HICON hIconSmall = NULL, BOOL bAutoDestroyIcon = FALSE, BOOL bAlphaBlendIcon = FALSE);

// Overridden
    void SetCheck(BOOL bCheck = TRUE);
    void DrawImage(CDC* pDC, RibbonImageType type, CRect rectImage);

// Attributes
private:
    BOOL m_bChecked;

// Helper
private:
    void DrawCheckmark(CDC* pDC, int CheckmarkResourceBitmapID, RECT *r);
    void PremultiplyBitmapAlpha(HDC hDC, HBITMAP hBmp);
};

以下是类函数定义:

CMFCRibbonButtonEx::CMFCRibbonButtonEx() : CMFCRibbonButton() { }
CMFCRibbonButtonEx::CMFCRibbonButtonEx(UINT nID, LPCTSTR lpszText, int nSmallImageIndex, int nLargeImageIndex, BOOL bAlwaysShowDescription)
    : CMFCRibbonButton(nID, lpszText, nSmallImageIndex, nLargeImageIndex, bAlwaysShowDescription) { }
CMFCRibbonButtonEx::CMFCRibbonButtonEx(UINT nID, LPCTSTR lpszText, HICON hIcon, BOOL bAlwaysShowDescription, HICON hIconSmall, BOOL bAutoDestroyIcon, BOOL bAlphaBlendIcon)
    : CMFCRibbonButton(nID, lpszText, hIcon, bAlwaysShowDescription , hIconSmall, bAutoDestroyIcon, bAlphaBlendIcon) { }
void CMFCRibbonButtonEx::SetCheck(BOOL bCheck)
{
    m_bChecked = bCheck;
}
void CMFCRibbonButtonEx::DrawImage(CDC* pDC, RibbonImageType type, CRect rectImage)
{
    CMFCRibbonButton::DrawImage(pDC, type, rectImage);
    if (type == RibbonImageLarge && m_bChecked) 
        DrawCheckmark(pDC, IDB_BIG_ICON_CHECKMARK, &rectImage);
}
void CMFCRibbonButtonEx::DrawCheckmark(CDC* pDC, int CheckmarkResourceBitmapID, RECT *r)
{
    HDC  hdc;
    CDC  *dc;
    CDC dcMem;
    CBitmap cbm;

    VERIFY(hdc = pDC->m_hDC);
    VERIFY(dc = pDC);

    dcMem.CreateCompatibleDC(dc);

    cbm.LoadBitmap(CheckmarkResourceBitmapID);
    PremultiplyBitmapAlpha(dcMem.m_hDC, cbm);
    SelectObject(dcMem.m_hDC, cbm.m_hObject);

    BLENDFUNCTION bf;
    bf.BlendOp = AC_SRC_OVER;
    bf.BlendFlags = 0;
    bf.SourceConstantAlpha = 255;
    bf.AlphaFormat = AC_SRC_ALPHA;
    ::AlphaBlend(hdc, r->left, r->top, r->right-r->left, r->bottom-r->top, dcMem, 0, 0, 32, 32, bf);

    VERIFY(dcMem.DeleteDC());
}
void CMFCRibbonButtonEx::PremultiplyBitmapAlpha(HDC hDC, HBITMAP hBmp)
{
   BITMAP bm = { 0 };
   GetObject(hBmp, sizeof(bm), &bm);
   BITMAPINFO* bmi = (BITMAPINFO*) _alloca(sizeof(BITMAPINFOHEADER) + (256 * sizeof(RGBQUAD)));
   ::ZeroMemory(bmi, sizeof(BITMAPINFOHEADER) + (256 * sizeof(RGBQUAD)));
   bmi->bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
   BOOL bRes = ::GetDIBits(hDC, hBmp, 0, bm.bmHeight, NULL, bmi, DIB_RGB_COLORS);
   if( !bRes || bmi->bmiHeader.biBitCount != 32 ) return;
   LPBYTE pBitData = (LPBYTE) ::LocalAlloc(LPTR, bm.bmWidth * bm.bmHeight * sizeof(DWORD));
   if( pBitData == NULL ) return;
   LPBYTE pData = pBitData;
   ::GetDIBits(hDC, hBmp, 0, bm.bmHeight, pData, bmi, DIB_RGB_COLORS);
   for( int y = 0; y < bm.bmHeight; y++ ) {
      for( int x = 0; x < bm.bmWidth; x++ ) {
         pData[0] = (BYTE)((DWORD)pData[0] * pData[3] / 255);
         pData[1] = (BYTE)((DWORD)pData[1] * pData[3] / 255);
         pData[2] = (BYTE)((DWORD)pData[2] * pData[3] / 255);
         pData += 4;
      }
   }
   ::SetDIBits(hDC, hBmp, 0, bm.bmHeight, pBitData, bmi, DIB_RGB_COLORS);
   ::LocalFree(pBitData);
}

IDB_BIG_ICON_CHECKMARK是带有alpha通道的32位bmp:checkmark icon Download here

可悲的是,在OnCmdMsg中,只保留了功能区框架创建的假CMFCRibbonButton,因此SetCheck()IsChecked() DrawImage()调用没有任何影响}}。您只需要在菜单的子项中找到真实的CMFCRibbonButtonEx,如下所示:

BOOL CEasyCashView::OnCmdMsg(UINT nID, int nCode, void* pExtra, AFX_CMDHANDLERINFO* pHandlerInfo) 
{
    ...

    else if (nID >= ID_MY_ITEMS_BASE && nID < ID_ITEMS_BASE+MAX_MY_ITEMS)
    {
        if (nCode == CN_COMMAND)
        {
            OnMyItemsCommand(nID);      
        }
        else if (nCode == CN_UPDATE_COMMAND_UI)
        {

            ((CCmdUI*)pExtra)->SetCheck(myItemsCheckedArray[nID-ID_MY_ITEMS_BASE] == TRUE); 
            // this won't have any effect, use code below

            CMFCRibbonButton* pMyMainMenuButton;
            if (pMyMainMenuButton = ((CMainFrame*)AfxGetMainWnd())->m_pMyMainMenuButton)
            {
                int i;
                for (i = 0; i < pMyMainMenuButton->GetSubItems().GetCount(); i++)
                    if (pMyMainMenuButton->GetSubItems()[i]->GetID() == nID)
                    {
                        ((CMFCRibbonButtonEx*)pMyMainMenuButton->GetSubItems()[i])->SetCheck(myItemsCheckedArray[nID-ID_MY_ITEMS_BASE] == TRUE);
                        break;
                    }
            }

            return TRUE;
        }
    }

如果有人知道如何将由CMFCRibbonButton维护的假CMFCRibbonBaseElement(或CCmdUI)与原始创建的CMFCRibbonButtonEx相关联,请留言。

答案 1 :(得分:-1)

  

“每个菜单项前面的复选框”

下图是你想要的吗?如果是,可以通过编辑功能区xml文件来实现。

enter image description here