如何让GDI+窗口仅背景透明而非整体透明?
实现GDI+窗口背景透明(仅背景,图像不透明)
原代码使用SetLayeredWindowAttributes的LWA_ALPHA会让整个窗口(包括绘制的图像)都半透明。要实现仅窗口背景透明、绘制的图像保持不透明,应该采用颜色键(Color Key)透明方案:指定窗口背景为一个唯一的、不会出现在目标图像中的颜色,让系统自动将该颜色区域设为透明。
解决方案步骤
- 注册窗口类时,将窗口背景色设为一个特定的专属颜色(确保你的图像中没有该颜色)。
- 创建窗口时必须使用
WS_EX_LAYERED扩展样式,这是分层窗口透明的前提。 - 在窗口创建完成(
WM_CREATE消息)时,调用SetLayeredWindowAttributes指定颜色键,仅启用LWA_COLORKEY标志,不使用LWA_ALPHA。 - 在
WM_PAINT中先填充窗口背景为该专属颜色,再绘制图像,这样未被图像覆盖的背景区域会被系统透明化,图像保留原本的不透明度。
修改后的完整代码
#include <windows.h> #include <gdiplus.h> LRESULT CALLBACK WindowProcessMessages(HWND hwnd, UINT msg, WPARAM param, LPARAM lparam); void draw(HDC hdc, RECT clientRect); // 定义用于透明的专属背景色(确保图像中没有这个颜色,可根据需求替换) #define TRANSPARENT_BG_COLOR RGB(0, 0, 0) int WINAPI WinMain(HINSTANCE currentInstance, HINSTANCE previousInstance, PSTR cmdLine, INT cmdCount) { // 初始化GDI+ Gdiplus::GdiplusStartupInput gdiplusStartupInput; ULONG_PTR gdiplusToken; Gdiplus::GdiplusStartup(&gdiplusToken, &gdiplusStartupInput, nullptr); // 注册窗口类 const char* CLASS_NAME = "myWin32WindowClass"; WNDCLASS wc{}; wc.hInstance = currentInstance; wc.lpszClassName = CLASS_NAME; wc.hCursor = LoadCursor(nullptr, IDC_ARROW); wc.hbrBackground = CreateSolidBrush(TRANSPARENT_BG_COLOR); // 设置背景刷为透明专属色 wc.lpfnWndProc = WindowProcessMessages; RegisterClass(&wc); // 创建分层窗口(可选WS_EX_TOPMOST让窗口置顶) HWND hwnd = CreateWindowEx(WS_EX_LAYERED | WS_EX_TOPMOST, CLASS_NAME, "Drawing Image", WS_POPUP | WS_VISIBLE, CW_USEDEFAULT, CW_USEDEFAULT, 800, 600, nullptr, nullptr, currentInstance, nullptr); // 消息循环 MSG msg{}; while (GetMessage(&msg, nullptr, 0, 0)) { TranslateMessage(&msg); DispatchMessage(&msg); } Gdiplus::GdiplusShutdown(gdiplusToken); return 0; } LRESULT CALLBACK WindowProcessMessages(HWND hwnd, UINT msg, WPARAM param, LPARAM lparam) { HDC hdc; PAINTSTRUCT ps; RECT clientRect; switch (msg) { case WM_CREATE: // 设置分层窗口属性:仅TRANSPARENT_BG_COLOR颜色的区域会被透明化 SetLayeredWindowAttributes(hwnd, TRANSPARENT_BG_COLOR, 0, LWA_COLORKEY); return 0; case WM_PAINT: hdc = BeginPaint(hwnd, &ps); GetClientRect(hwnd, &clientRect); // 先填充整个客户区为透明专属色,确保空白区域都是该颜色 FillRect(hdc, &clientRect, (HBRUSH)GetClassLongPtr(hwnd, GCLP_HBRBACKGROUND)); // 绘制图像 draw(hdc, clientRect); EndPaint(hwnd, &ps); return 0; case WM_DESTROY: PostQuitMessage(0); return 0; default: return DefWindowProc(hwnd, msg, param, lparam); } } void draw(HDC hdc, RECT clientRect) { Gdiplus::Graphics gf(hdc); // 加载图像(确保图像中没有TRANSPARENT_BG_COLOR,否则对应区域也会被透明) Gdiplus::Bitmap bmp(L"image.png"); // 绘制图像到窗口(示例在(10,10)位置绘制,可自行调整坐标) gf.DrawImage(&bmp, 10, 10); }
关键改动说明
- 专属透明色:
TRANSPARENT_BG_COLOR可替换为如RGB(255,0,255)(品红色)这类极少出现在普通图像中的颜色,避免误透明图像内容。 - 分层属性设置:仅在
WM_CREATE中调用一次SetLayeredWindowAttributes,仅启用LWA_COLORKEY,确保只有背景色区域透明,图像不受影响。 - 背景填充:在
WM_PAINT中先填充窗口背景,保证所有未被图像覆盖的区域都是专属透明色,最终被系统处理为透明。
内容的提问来源于stack exchange,提问作者joeymalvinni
相关产品推荐
相关产品推荐

