CMFCStatusBar :: SetPaneIcon是否支持alpha图标?

时间:2015-09-15 15:25:27

标签: c++ mfc mfc-feature-pack

我的应用程序设置状态栏(类CMFCStatusBar)中窗格的图标。此任务只有一种方法 - CMFCStatusBar :: SetPaneIcon()。但是如果图标有alpha通道,则此方法会加载错误的图像(在黑色背景上)。 我查看了源代码,我看到CMFCStatusBar为每个窗格使用内部HIMAGELIST。所有这些HIMAGELIST都使用标志ILC_MASK创建ILC_COLORDDB,而不是ILC_COLOR32或ILC_COLOR24。

这是一个错误!

那么,有没有办法在CMFCStatusBar窗格中使用带alpha通道的图标?

示例:

HICON hIcon = ::LoadImage(hModule, MAKEINTRESOURCE(nIconID), IMAGE_ICON, 16, 16, LR_DEFAULTCOLOR);
m_StatusBar.SetPaneIcon(m_StatusBar.CommandToIndex(ID_INDICATOR_1), hIcon);

2 个答案:

答案 0 :(得分:1)

Microsoft从BCG toolkit开发了CMFC类(Feature Pack)。如果您将CMFCStatusBar::SetPaneIcon()方法与同一类中的 BCG 方法进行比较,您会发现一些细微差别。

BCG使用alpha混合标志定义其方法。该方法如下:

void CBCGPStatusBar::SetPaneIcon (int nIndex, HBITMAP hBmp,
            COLORREF clrTransparent, BOOL bUpdate, BOOL bAlphaBlend/* = FALSE*/)

CMFC等效项删除'bAlphaBlend'标志。 比较方法代码,您将看到BCG使用以下已从CMFC版本中删除的代码:

DWORD dwFlags = ILC_MASK | ILC_COLORDDB;
if (bAlphaBlend)
{
    dwFlags = ILC_COLOR32;
}

pSBP->hImage = ::ImageList_Create (pSBP->cxIcon, pSBP->cyIcon, dwFlags, 1, 0);

我不确定为什么CMFC版本差异太大(微软可能有正当理由),但是,我已经在下面加入了BCG版本。我会研究BCG版本,并可能从该代码创建自己的'SetPaneIcon'方法(风险自负)。

void CBCGPStatusBar::SetPaneIcon (int nIndex, HBITMAP hBmp,
                                 COLORREF clrTransparent, BOOL bUpdate, BOOL bAlphaBlend/* = FALSE*/)
{
    ASSERT_VALID(this);

    CBCGStatusBarPaneInfo* pSBP = _GetPanePtr(nIndex);
    if (pSBP == NULL)
    {
        ASSERT (FALSE);
        return;
    }

    // Disable animation (if exist):
    SetPaneAnimation (nIndex, NULL, 0, FALSE);

    if (hBmp == NULL)
    {
        if (pSBP->hImage != NULL)
        {
            ::ImageList_Destroy (pSBP->hImage);
        }

        pSBP->hImage = NULL;

        if (bUpdate)
        {
            InvalidatePaneContent (nIndex);
        }

        return;
    }

    BITMAP bitmap;
    ::GetObject (hBmp, sizeof (BITMAP), &bitmap);

    if (pSBP->hImage == NULL)
    {
        pSBP->cxIcon = bitmap.bmWidth;
        pSBP->cyIcon = bitmap.bmHeight;

        DWORD dwFlags = ILC_MASK | ILC_COLORDDB;
        if (bAlphaBlend)
        {
            dwFlags = ILC_COLOR32;
        }

        pSBP->hImage = ::ImageList_Create (pSBP->cxIcon, pSBP->cyIcon, dwFlags, 1, 0);
        RecalcLayout ();
    }
    else
    {
        ASSERT (pSBP->cxIcon == bitmap.bmWidth);
        ASSERT (pSBP->cyIcon == bitmap.bmHeight);

        ::ImageList_Remove (pSBP->hImage, 0);
    }

    //---------------------------------------------------------
    // Because ImageList_AddMasked changes the original bitmap,
    // we need to create a copy:
    //---------------------------------------------------------
    HBITMAP hbmpCopy = (HBITMAP) ::CopyImage (hBmp, IMAGE_BITMAP, 0, 0, 0);

    if (bAlphaBlend)
    {
        ::ImageList_Add (pSBP->hImage, hbmpCopy, NULL);
    }
    else    
    {
        ::ImageList_AddMasked (pSBP->hImage, hbmpCopy, clrTransparent);
    }

    ::DeleteObject (hbmpCopy);

    if (bUpdate)
    {
        InvalidatePaneContent (nIndex);
    }
}

答案 1 :(得分:0)

我的解决方案,基于 rrirower 代码。

CMFCStatusBarPaneInfo* CMyStatusBar::GetPane(int nIndex) const {
    if (nIndex == 255 && m_nCount < 255) {
        // Special case for the simple pane
        for (int i = 0; i < m_nCount; i++)
        {
                CMFCStatusBarPaneInfo* pSBP = GetPane(i);
                ENSURE(pSBP != NULL);

            if (pSBP->nStyle & SBPS_STRETCH) {
                return pSBP;
            }
        }
    }

    if (nIndex < 0 || nIndex >= m_nCount) {
        return NULL;
    }

    if (m_pData == NULL) {
        ASSERT(FALSE);
        return NULL;
    }

    return((CMFCStatusBarPaneInfo*)m_pData) + nIndex;
}


void CMyStatusBar::SetPaneIcon(int nIndex, HICON hIcon, BOOL bUpdate /*= TRUE*/)
{
    ASSERT_VALID(this);

    CMFCStatusBarPaneInfo* pSBP = GetPane(nIndex);
    if (pSBP == NULL)
    {
        ASSERT(FALSE);
        return;
    }

    // Disable animation(if exist):
    SetPaneAnimation(nIndex, NULL, 0, FALSE);

    if (hIcon == NULL)
    {
        if (pSBP->hImage != NULL)
        {
            ::ImageList_Destroy(pSBP->hImage);
        }

        pSBP->hImage = NULL;

        if (bUpdate)
        {
            InvalidatePaneContent(nIndex);
        }

        return;
    }

    ICONINFO iconInfo;
    ::GetIconInfo(hIcon, &iconInfo);

    BITMAP bitmap;
    ::GetObject(iconInfo.hbmColor, sizeof(BITMAP), &bitmap);

    ::DeleteObject(iconInfo.hbmColor);
    ::DeleteObject(iconInfo.hbmMask);

    if (pSBP->hImage == NULL)
    {
        pSBP->cxIcon = bitmap.bmWidth;
        pSBP->cyIcon = bitmap.bmHeight;

        pSBP->hImage = ::ImageList_Create(pSBP->cxIcon, pSBP->cyIcon, ILC_COLOR32 | ILC_MASK, 1, 0);
        ::ImageList_AddIcon(pSBP->hImage, hIcon);

        RecalcLayout();
    }
    else
    {
        ASSERT(pSBP->cxIcon == bitmap.bmWidth);
        ASSERT(pSBP->cyIcon == bitmap.bmHeight);

        ::ImageList_ReplaceIcon(pSBP->hImage, 0, hIcon);
    }

    if (bUpdate)
    {
        InvalidatePaneContent(nIndex);
    }
}