[英]Creating a transparent window in C++ Win32
我正在創建一個非常簡單的 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;
}
需要注意的一件事是應用程序始終停靠在屏幕左側並且不會移動。 但是,當用戶打開、關閉或移動應用程序下方的窗口時,應用程序下方的內容可能會發生變化。
當應用程序第一次啟動時,它看起來很完美。 PNG 的透明(和半透明)部分完美地顯示出來。 但是,當應用程序下面的背景發生變化時,背景不會更新,它只是與應用程序首次啟動時保持不變。 事實上,WM_PAINT(或 WM_ERASEBKGND 在背景改變時不會被調用)。
我已經玩了很長一段時間,並且已經接近 100% 正確,但還沒有完全正確。 例如,我嘗試將背景設置為 (HBRUSH) NULL_BRUSH,並且嘗試處理 WM_ERASEBKGND。
當窗口下的內容發生變化時,如何讓窗口重新繪制?
通過使用本系列第 1 部分和第 2 部分中的代碼,我能夠完全按照自己的意願行事:
- 第 1 部分: 創建 HBITMAP存檔
- 第 2 部分: 顯示窗口存檔
那些博客文章談論在 Win32 C++ 中顯示啟動畫面,但它幾乎與我需要做的相同。 我相信我缺少的部分是,我需要使用具有正確BLENDFUNCTION
參數的UpdateLayeredWindow
函數,而不是僅使用 GDI+ 將 PNG 繪制到窗口。 我將粘貼下面的 SetSplashImage 方法,該方法可以在上面鏈接的第 2 部分中找到:
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存檔功能,這允許您設置將變為透明的遮罩顏色,從而允許背景顯示出來。
您還需要使用分層標志配置您的窗口,例如:
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 文章中的方法:
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.