C++ MFC实现透明对话框并绘制带透明效果图片的问题
在MFC对话框中实现透明背景并显示带透明效果的图片
我想在C++ MFC中实现对话框透明,同时在对话框里绘制带透明效果的图片。以下是我写的代码,但最终显示的图片没有透明效果,求解决方法。
1. 背景透明实现代码
cb.CreateSolidBrush(RGB(0, 128, 0)); hbr = (HBRUSH) cb;
LONG lStyle = ::GetWindowLong(GetSafeHwnd(), GWL_EXSTYLE); lStyle |= WS_EX_LAYERED; ::SetWindowLong(GetSafeHwnd(), GWL_EXSTYLE, lStyle); SetLayeredWindowAttributes(RGB(0, 128, 0), 0, LWA_COLORKEY);
2. 绘制带透明效果图片的代码
IStream* pStream = NULL; HRESULT hr = SHCreateStreamOnFile(L"MY_IMAGE.png", STGM_READ | STGM_SHARE_DENY_WRITE, &pStream); if (SUCCEEDED(hr)) { CImage image; image.Load(pStream); image.Save(L"test.png"); // Correct Image HBITMAP hBitmap; hBitmap = image.Detach(); BITMAP bmp; GetObject(hBitmap, sizeof(bmp), &bmp); int width = bmp.bmWidth; int height = bmp.bmHeight; CDC* pDC = GetDC(); CDC hDCMem; hDCMem.CreateCompatibleDC(pDC); HBITMAP hBmpOld = (HBITMAP)hDCMem.SelectObject(hBitmap); CRect rect; GetClientRect(rect); int imageWidth = bmp.bmWidth; int imageHeight = bmp.bmHeight; int screenWidth = rect.Width(); int screenHeight = rect.Height(); for (int i = 0; i < screenWidth; i += imageWidth) { for (int j = 0; j < screenHeight; j += imageHeight) { pDC->BitBlt(i, j, bmp.bmWidth, bmp.bmHeight, &hDCMem, 0, 0, SRCCOPY); } } hDCMem.SelectObject(hBmpOld); DeleteObject(hBitmap); DeleteObject(image); DeleteDC(hDCMem); }
问题原因及解决方法
你用BitBlt的SRCCOPY模式无法处理PNG的Alpha通道透明,而且DeleteObject(image)是错误操作(CImage是封装类,无需手动用DeleteObject释放)。按以下步骤修改即可:
1. 替换绘制逻辑,用AlphaBlend处理透明
AlphaBlend函数支持带Alpha通道的图片渲染,修改后的绘制代码如下:
IStream* pStream = NULL; HRESULT hr = SHCreateStreamOnFile(L"MY_IMAGE.png", STGM_READ | STGM_SHARE_DENY_WRITE, &pStream); if (SUCCEEDED(hr)) { CImage image; image.Load(pStream); pStream->Release(); // 释放流资源 CDC* pDC = GetDC(); CDC memDC; memDC.CreateCompatibleDC(pDC); HBITMAP hOldBmp = (HBITMAP)memDC.SelectObject(image); CRect clientRect; GetClientRect(clientRect); // 配置Alpha混合参数 BLENDFUNCTION blend = {0}; blend.BlendOp = AC_SRC_OVER; blend.BlendFlags = 0; blend.SourceConstantAlpha = 255; // 0-255,数值越小越透明 blend.AlphaFormat = AC_SRC_ALPHA; // 启用图片自身的Alpha通道 // 平铺绘制图片 for (int i = 0; i < clientRect.Width(); i += image.GetWidth()) { for (int j = 0; j < clientRect.Height(); j += image.GetHeight()) { AlphaBlend(pDC->m_hDC, i, j, image.GetWidth(), image.GetHeight(), memDC.m_hDC, 0, 0, image.GetWidth(), image.GetHeight(), blend); } } memDC.SelectObject(hOldBmp); ReleaseDC(pDC); // CImage对象会自动释放资源,无需手动DeleteObject }
2. 确认对话框透明设置的正确性
背景透明代码要放在OnInitDialog中,同时重写OnCtlColor返回对应颜色的画刷,确保样式和颜色一致:
BOOL CYourDlg::OnInitDialog() { CDialogEx::OnInitDialog(); // 设置分层窗口样式 LONG lStyle = ::GetWindowLong(GetSafeHwnd(), GWL_EXSTYLE); lStyle |= WS_EX_LAYERED; ::SetWindowLong(GetSafeHwnd(), GWL_EXSTYLE, lStyle); // 设置透明颜色键 SetLayeredWindowAttributes(RGB(0, 128, 0), 0, LWA_COLORKEY); return TRUE; } HBRUSH CYourDlg::OnCtlColor(CDC* pDC, CWnd* pWnd, UINT nCtlColor) { HBRUSH hbr = CDialogEx::OnCtlColor(pDC, pWnd, nCtlColor); static CBrush cb(RGB(0, 128, 0)); return cb; }
3. 关键注意事项
- 确保PNG图片本身带有有效Alpha通道(你保存的test.png正常,这一步没问题)。
- 不要用
image.Detach()分离HBITMAP,会丢失Alpha通道的格式信息。 - 资源释放时,
IStream必须调用Release(),CImage无需手动释放。
内容的提问来源于stack exchange,提问作者l_y
相关产品推荐
相关产品推荐

