我试图用alpha通道(通过AlphaBlend)绘制位图作为自己绘制的按钮的面。问题是我不确定如何绘制按钮的背景。按钮的位图是圆形的,按钮位于静态控件的顶部,该控件绘制矩形位图(通过SS_BITMAP)。它在第一次绘制时看起来很好,但随后的绘图最终将位图与DC中的剩余部分进行字母混合,因此边缘(alpha像素所在的地方)变得丑陋。我尝试将对话框背景复制到我在WM_DRAWITEM中获得的DC,但这只会让我获得对话框背景;它不能让我得到按钮下的静态控制部分。我该怎么做呢?
我的位图与此相似,除了对话框有一个自定义背景(在WM_ERASEBKGND期间绘制的位图),矩形进一步向水平方向扩展。
我找到了一个更好的解决方案。它基本上与我以前的解决方案结构相同,只是没有复制设备上下文中已经存在的内容到位图,我发送所有相关控件WM_ERASEBKGND和WM_PRINTCLIENT消息。我基于这篇知识库文章中的代码。
嗯,我找到了一个适合我需要的方法;我不知道这是不是理想的解决方案,但如果没人能想出更好的办法,那么几天后我会接受我自己的答案。
所以这是我使用的技巧(从使用ATL的CImage转换到原始的Win32 api,所以可能会有一些错误):
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;
}