与大型图像和复选框功能区按钮项(Ribbon button items with large ima

2019-10-19 12:50发布

我有连接到这样的分裂功能区按钮菜单(VS2008,功能包):

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菜单? 如果没有,什么是最好的可能的解决方法?

Answer 1:

我发现了一个解决方法可用通过alpha混合的绿色圆圈与它在图标上勾选检查大图标 - 同样的解决方案,Windows使用,以纪念在控制面板中的默认音频设备或打印机:

这是我的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是一个32位的BMP的alpha通道: 在这里下载

不幸的是,在只的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 ,请给我留下了评论。



Answer 2:

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

是下面的图片,你在找什么? 如果是的话,这可以通过编辑功能区XML文件来实现。



文章来源: Ribbon button items with large images and checkboxes