开发者

How do I alphablend a bitmap onto an owner-drawn button that overlaps other windows?

开发者 https://www.devze.com 2023-04-12 18:08 出处:网络
I am trying to draw a bitmap with an alpha channel (via AlphaBlend) as the face of an owner-drawn button.The problem is that I\'m not sure how to draw the background of the button.The button\'s bitmap

I am trying to draw a bitmap with an alpha channel (via AlphaBlend) as the face of an owner-drawn button. The problem is that I'm not sure how to draw the background of the button. The button's bitmap is circular, and the button is on top of a static control that draws a rectangular bitmap (via SS_BITMAP). It looks fine the first time it is drawn, but subsequent drawings end up alphablending the bitmap with its remains in the DC so the edges (where the alpha pixels lie) get ugly. I tried copying the dialog background to the DC I get in WM_DRAWITEM, but that only gets me the dialog background; it does not get me the part of the static control that is under the button. How do I do this?

My bitmaps are similar to this, except the dialog has a custom background (bitmap drawn during WM_ERASE开发者_开发百科BKGND) and the rectangle extends further out horizontally.


I found a better solution. It's basically the same structure as my previous solution, only instead of copying what's already on the device context to a bitmap I send all the relevant controls WM_ERASEBKGND and WM_PRINTCLIENT messages. I based it off of the code in this KB article.


Well, I found one method that works for my needs; I don't know if it's the ideal solution, but if nobody can come up with anything better then I'll accept my own answer in a few days.

So here's the trick I'm using (transposed from use of ATL's CImage to raw Win32 APIs, so there could be some mistakes):

LRESULT CALLBACK MyButtonProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
    switch(uMsg)
    {
    case WM_ERASEBKGND:
        if(!m_BackgroundBitmap)
        {
            // first time the button's background is being erased
            // all the controls below it in the z-order have already
            // been drawn at this point, so take a snapshot of the
            // contents of the device context to use in the future
            RECT rc;
            GetWindowRect(hWnd, &rc);
            int cx = rc.right - rc.left;
            int cy = rc.bottom - rc.top;
            HDC hDC = (HDC)wParam;
            HDC hDCMem = CreateCompatibleDC(hDC);
            m_BackgroundBitmap = CreateCompatibleBitmap(hDC, cx, cy);
            HBITMAP hBmpOld = (HBITMAP)SelectObject(hDCMem, m_BackgroundBitmap);
            BitBlt(hDCMem, 0, 0, cx, cy, hDC, 0, 0, SRCCOPY);
            SelectObject(hDCMem, hBmpOld);
            hBmpOld = NULL;
            DeleteDC(hDCMem);
            hDCMem = NULL;
        }
        break;
    }
    return CallWindowProc(m_PrevProc, hWnd, uMsg, wParam, lParam);
}

INT_PTR CALLBACK MyDialogProc(HWND hDlg, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
    switch(uMsg)
    {
    case WM_INITDIALOG:
        // load resources, subclass buttons, etc.
        return TRUE;
    case WM_DRAWITEM:
        // figure out if display needs to be updated, which face to draw, etc.
        HDC hDC = lpDrawItemStruct->hDC;
        HDC hDCMem = CreateCompatibleDC(hDC);
        // first copy the background from the snapshot taken earlier
        HBITMAP hBmpOld = (HBITMAP)SelectObject(hDCMem, m_BackgroundBitmap);
        BitBlt(hDC, x, y, w, h, hDCMem, 0, 0, SRCCOPY);
        // then alphablend the button face on top of that
        SelectObject(hDCMem, m_AlphaButtonBitmap);
        AlphaBlend(hDC, x, y, w, h, hDCMem, 0, 0, w, h, bf);
        SelectObject(hDCMem, hBmpOld);
        hBmpOld = NULL;
        DeleteDC(hDCMem);
        hDCMem = NULL;
        return TRUE;
    }
    return FALSE;
}
0

精彩评论

暂无评论...
验证码 换一张
取 消

关注公众号