CMFCButton透明背景按钮绘制残留问题求助
问题核心
你遇到的图像残留问题,本质是每次绘制按钮状态前,兼容DC的画布没有被正确清空——CreateCompatibleBitmap创建的位图初始内容是未定义的(可能包含上一次绘制的残留数据),新绘制的PNG叠加在旧内容上就会出现残影。
修复思路
要解决这个问题,需要在绘制当前状态的PNG前,先将按钮所在区域的父窗口背景绘制到兼容DC,这样画布会被重置为和窗口一致的干净背景,再绘制按钮的透明PNG时,透明区域会显示窗口背景,不会残留旧图像。
修改后的完整代码
void CAlphaButton::DrawButton(HDC hDestDC) { CRect rc; GetClientRect(rc); int nWidth = rc.Width(); int nHeight = rc.Height(); HDC hDC = CreateCompatibleDC(hDestDC); HBITMAP hBitmap = CreateCompatibleBitmap(hDestDC, nWidth, nHeight); HBITMAP hOldBitmap = (HBITMAP)SelectObject(hDC, hBitmap); // 关键修复:绘制父窗口背景到兼容DC,清除上一次的图像残留 CWnd* pParent = GetParent(); if (pParent != nullptr) { HDC hParentDC = pParent->GetDC(); if (hParentDC != nullptr) { CRect rcScreen = rc; ClientToScreen(rcScreen); pParent->ScreenToClient(rcScreen); // 将父窗口对应区域的背景复制到兼容DC BitBlt(hDC, 0, 0, nWidth, nHeight, hParentDC, rcScreen.left, rcScreen.top, SRCCOPY); pParent->ReleaseDC(hParentDC); } } // 根据鼠标状态绘制对应PNG if (m_bDisable) { // 可添加禁用状态的绘制逻辑 } else if (m_bDown) { if (!m_png_Pushed.IsNull()) { m_png_Pushed.Draw(hDC, rc); } } else if (m_bOver) { if (!m_png_Over.IsNull()) { m_png_Over.Draw(hDC, rc); } } else { if (!m_png_Normal.IsNull()) { m_png_Normal.Draw(hDC, rc); } } if (m_bSingleImage) { if (!m_idb_image.IsNull()) { m_idb_image.Draw(hDC, rc); } } // Alpha混合绘制到目标DC BLENDFUNCTION blend; blend.BlendOp = AC_SRC_OVER; blend.BlendFlags = 0; blend.SourceConstantAlpha = 255; blend.AlphaFormat = AC_SRC_ALPHA; AlphaBlend(hDestDC, 0, 0, nWidth, nHeight, hDC, 0, 0, nWidth, nHeight, blend); // 资源清理 SelectObject(hDC, hOldBitmap); DeleteObject(hBitmap); DeleteDC(hDC); }
额外说明
- 如果你的按钮是在透明窗口上使用,上述方法不适用,此时需要创建带Alpha通道的DIB位图,初始将整个画布设为全透明:
// 替换CreateCompatibleBitmap的代码 BITMAPINFO bmi = {0}; bmi.bmiHeader.biSize = sizeof(BITMAPINFOHEADER); bmi.bmiHeader.biWidth = nWidth; bmi.bmiHeader.biHeight = -nHeight; // 顶部为原点 bmi.bmiHeader.biPlanes = 1; bmi.bmiHeader.biBitCount = 32; bmi.bmiHeader.biCompression = BI_RGB; void* pBits = nullptr; HBITMAP hBitmap = CreateDIBSection(hDestDC, &bmi, DIB_RGB_COLORS, &pBits, nullptr, 0); // 初始化为全透明 memset(pBits, 0, nWidth * nHeight * 4); - 确保在鼠标状态变化(如
OnMouseMove、OnLButtonDown、OnLButtonUp)时调用Invalidate()触发重绘,否则按钮状态不会及时更新。
内容的提问来源于stack exchange,提问作者al072
相关产品推荐
相关产品推荐

