Displaying a transparent bitmap in a button with the BS_OWNERDRAW flag

156 Views Asked by At

I have a problem when displaying a transparent bitmap on the button. The new images are simply superimposed on each other, I couldn't find anything sensible on the Internet about this.

Here is the code I have:

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: So, I added the FillRect, but now the image just disappears after I press the button and release it.

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

Demonstration2

UPD_2: I finally found some problems, AlphaBlend returns errors after the third call. Error code: 87 (The parameter is incorrect). I don't understand which one? I checked in the debugger - hdcDest, hdcSrc seem to be normal, not NULL, other parameters do not change

Demonstration Problem demonstration

1

There are 1 best solutions below

8
YangXiaoPo-MSFT On

You need to invalidate or erase the area as @JonathanPotter said.

There is a Microsoft sample ChooseFont which explains this.

/******************************************************************
*                                                                 *
* 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;
}

Edit:
InvalidateRect just issues a WM_PAINT message to a window whenever its update region is not empty and there are no other messages in the application queue for that window.

It's erased in 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));

        ...
    }