在带有 BS_OWNERDRAW 标志的按钮中显示透明位图

Displaying a transparent bitmap in a button with the BS_OWNERDRAW flag

提问人:MyDoomH 提问时间:10/23/2023 最后编辑:MyDoomH 更新时间:10/26/2023 访问量:125

问:

在按钮上显示透明位图时出现问题。新图像只是相互叠加,我在互联网上找不到任何关于这一点的合理信息。

这是我拥有的代码:

VOID DrawButton(LPDRAWITEMSTRUCT DrawStruct, HBITMAP* BitmapArray)
{
    HBITMAP CurrentBitmap = BitmapArray[BM_UP];

    switch (DrawStruct->itemAction)
    {
    case ODA_SELECT:
        if (DrawStruct->itemState & ODS_SELECTED)
        {
            if (DrawStruct->itemState & ODS_FOCUS)
                CurrentBitmap = BitmapArray[BM_DOWN_FOCUS];
            else
                CurrentBitmap = BitmapArray[BM_DOWN];
        }
        break;
    case ODA_DRAWENTIRE:
        if (DrawStruct->itemState & ODS_DISABLED)
            CurrentBitmap = BitmapArray[BM_DISABLE];
        break;
    case ODA_FOCUS:
        if (DrawStruct->itemState & ODS_FOCUS)
            CurrentBitmap = BitmapArray[BM_FOCUS];
        break;
    }
    
    HDC CompatibleDC = CreateCompatibleDC(DrawStruct->hDC);
    HBITMAP hOld = (HBITMAP)SelectObject(CompatibleDC, CurrentBitmap);
    SelectObject(CompatibleDC, CurrentBitmap);
    AlphaBlend(DrawStruct->hDC, 0, 0, 50, 24, CompatibleDC, 0, 0, 50, 24, { AC_SRC_OVER, 0, 255, AC_SRC_ALPHA });
    SelectObject(DrawStruct->hDC, hOld);
    DeleteDC(CompatibleDC);
    DeleteObject(CurrentBitmap);
}

UPD:所以,我添加了 FillRect,但现在在我按下按钮并释放它后,图像就消失了。

VOID DrawButton(LPDRAWITEMSTRUCT DrawStruct, HBITMAP* BitmapArray)
{
    ...
    FillRect(DrawStruct->hDC, &DrawStruct->rcItem, CreateSolidBrush(RGB(127, 127, 127)));
    HDC CompatibleDC = CreateCompatibleDC(DrawStruct->hDC);
    ...
}

Demonstration2

UPD_2:我终于发现了一些问题,AlphaBlend 在第三次调用后返回错误。错误代码:87(参数不正确)。我不明白是哪一个?我检查了调试器 - hdcDest,hdcSrc 似乎正常,不是 NULL,其他参数没有改变

Demonstration Problem demonstration

C++ WinAPI 按钮 透明度 alpha-transparency

评论

0赞 Jonathan Potter 10/23/2023
一旦你画了一些东西,它就会一直画出来,直到有什么东西擦掉它或画到顶部。
0赞 IInspectable 10/28/2023
在删除它之前,您永远不会选择退出。这是一个错误。您删除的频率也高于创建频率。CurrentBitmapCompatibleDCCurrentBitmap

答:

-1赞 YangXiaoPo-MSFT 10/23/2023 #1

正如@JonathanPotter所说,您需要使该区域失效或擦除。

有一个 Microsoft 示例 ChooseFont 可以解释这一点。

/******************************************************************
*                                                                 *
* ChooseFontDialog::OnFontSizeSelect                              *
*                                                                 *
* Record the new font size and redraw the sample text.            *
*                                                                 *
******************************************************************/

HRESULT ChooseFontDialog::OnFontSizeSelect()
{
    HRESULT hr = S_OK;

    // Signal the sample text window to redraw itself.
    InvalidateRect(GetDlgItem(m_dialog, ID_SAMPLE_BOX), NULL, false);

    return hr;
}

编辑:
InvalidateRect 只是在窗口的更新区域不为空且该窗口的应用程序队列中没有其他消息时向窗口发出消息。
WM_PAINT

它被擦除在 .WM_DRAWITEM

    if (SUCCEEDED(hr))
    {
        // Fill the DWrite surface with the background color
        HDC dwriteDC = textRenderer->GetDC();
        SetDCBrushColor(dwriteDC, GetSysColor(COLOR_BTNFACE));
        FillRect(dwriteDC, &sampleBounds, GetStockBrush(DC_BRUSH));

        ...
    }

评论

0赞 MyDoomH 10/23/2023
InvalidateRect 将再次调用 DrawButton...
0赞 IInspectable 10/24/2023
“你需要 [...]擦除该区域“ - 我相信有比将参数作为参数传递到 InvalidateRect 调用更有前途的方法来实现这一目标。falsebErase
0赞 MyDoomH 10/25/2023
因此,我添加了 FillRect,但现在图像消失了。UPD 中附有一个示例。
0赞 MyDoomH 10/26/2023
我终于发现了一些问题,AlphaBlend 在第三次调用后返回错误。错误代码:87(参数不正确)。我不明白是哪一个?我检查了调试器 - hdcDest,hdcSrc 似乎正常,不是 NULL,其他参数没有改变