簡體   English   中英

在 C++ Win32 中創建透明窗口

[英]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 部分中的代碼,我能夠完全按照自己的意願行事:

使用 C++ 顯示啟動畫面


那些博客文章談論在 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 文章中的方法:

帶有適用於 Windows 2000 及更高版本的標准控件的酷炫、半透明和異形對話框

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM