用C ++ Win32创build一个透明的窗口
我创build的应该是一个非常简单的Win32 C ++应用程序,仅用于显示半透明的PNG。 该窗口不应该有任何铬,所有的不透明度应该在PNG本身进行控制。
我的问题是,当窗口下的内容改变时,窗口不会重新绘制,所以当应用程序最初启动时,PNG的透明区域与“窗口”下的内容“卡住”。
这里是我设置新窗口的那一行:
hWnd = CreateWindowEx(WS_EX_TOPMOST, szWindowClass, szTitle, WS_POPUP, 0, height/2 - 20, 40, 102, NULL, NULL, hInstance, 0);
对于RegisterClassEx的调用,我有这样的背景设置:
wcex.hbrBackground = (HBRUSH)0;
这是我的WM_PAINT消息处理程序:
case WM_PAINT: { hdc = BeginPaint(hWnd, &ps); Gdiplus::Graphics graphics(hdc); graphics.DrawImage(*m_pBitmap, 0, 0); EndPaint(hWnd, &ps); break; }
有一件事要注意的是,应用程序总是停靠在屏幕的左侧,不移动。 但是,当用户打开,closures或移动窗口时,应用程序下面的内容可能会改变。
应用程序首次启动时,看起来很完美。 透明(和simi透明)的PNG部分显示完美。 但是,当应用程序下面的背景发生变化时,背景不会更新,只是应用程序首次启动时保持不变。 实际上,WM_PAINT(或WM_ERASEBKGND在后台更改时不会被调用)。
我已经玩了很长一段时间,已经接近100%的权利,但不是那样。 例如,我试图设置背景(HBRUSH)NULL_BRUSH,我试着处理WM_ERASEBKGND。
当它下面的内容改变时,可以做些什么来重新绘制窗口?
通过使用本系列的第1部分和第2部分的代码,我能够完成我想要的function: http : //code.logos.com/blog/2008/09/displaying_a_splash_screen_with_c_introduction.html
那些博客文章正在讨论在Win32 C ++中显示一个启animation面,但是和我需要做的几乎完全相同。 我相信我遗漏的部分是,不是使用GDI +将PNG绘制到窗口,而是需要使用UpdateLayeredWindow函数和正确的BLENDFUNCTION参数。 我将粘贴下面的SetSplashImage方法,可以在上面的链接的第2部分find:
void SetSplashImage(HWND hwndSplash, HBITMAP hbmpSplash) { // get the size of the bitmap BITMAP bm; GetObject(hbmpSplash, sizeof(bm), &bm); SIZE sizeSplash = { bm.bmWidth, bm.bmHeight }; // get the primary monitor's info POINT ptZero = { 0 }; HMONITOR hmonPrimary = MonitorFromPoint(ptZero, MONITOR_DEFAULTTOPRIMARY); MONITORINFO monitorinfo = { 0 }; monitorinfo.cbSize = sizeof(monitorinfo); GetMonitorInfo(hmonPrimary, &monitorinfo); // center the splash screen in the middle of the primary work area const RECT & rcWork = monitorinfo.rcWork; POINT ptOrigin; ptOrigin.x = 0; ptOrigin.y = rcWork.top + (rcWork.bottom - rcWork.top - sizeSplash.cy) / 2; // create a memory DC holding the splash bitmap HDC hdcScreen = GetDC(NULL); HDC hdcMem = CreateCompatibleDC(hdcScreen); HBITMAP hbmpOld = (HBITMAP) SelectObject(hdcMem, hbmpSplash); // use the source image's alpha channel for blending BLENDFUNCTION blend = { 0 }; blend.BlendOp = AC_SRC_OVER; blend.SourceConstantAlpha = 255; blend.AlphaFormat = AC_SRC_ALPHA; // paint the window (in the right location) with the alpha-blended bitmap UpdateLayeredWindow(hwndSplash, hdcScreen, &ptOrigin, &sizeSplash, hdcMem, &ptZero, RGB(0, 0, 0), &blend, ULW_ALPHA); // delete temporary objects SelectObject(hdcMem, hbmpOld); DeleteDC(hdcMem); ReleaseDC(NULL, hdcScreen); }
使用SetLayeredWindowAttributes,这允许你设置一个将变为透明的遮罩颜色,从而允许背景透过。
http://msdn.microsoft.com/en-us/library/ms633540(VS.85).aspx
您还需要使用分层标志来configuration窗口,例如
SetWindowLong(hwnd, GWL_EXSTYLE, GetWindowLong(hwnd, GWL_EXSTYLE) | WS_EX_LAYERED);
之后,这很简单:
// Make red pixels transparent: SetLayeredWindowAttributes(hwnd, RGB(255,0,0), 0, LWA_COLORKEY);
当您的PNG包含您想要与背景混合的半透明像素时,这变得更加复杂。 你可以尝试看这个CodeProject文章中的方法:
用于Windows 2000及更高版本的带有标准控件的酷,半透明和形状对话框