Tworzenie przezroczystego okna w C++ Win32

Tworzę coś, co powinno być bardzo prostą aplikacją Win32 C++, której jedynym celem jest wyświetlanie tylko półprzezroczystego PNG. Okno nie powinno mieć chrome, a cała krycie powinna być kontrolowana w samym PNG.

Mój problem polega na tym, że okno nie przemalowuje się, gdy zmienia się Zawartość pod oknem, więc przezroczyste obszary PNG są "zablokowane" z tym, co było pod oknem, gdy aplikacja była początkowo uruchamiana.

Oto linia, w której ustawiłem nowy Okno:

hWnd = CreateWindowEx(WS_EX_TOPMOST, szWindowClass, szTitle, WS_POPUP, 0, height/2 - 20, 40, 102, NULL, NULL, hInstance, 0);

Dla wywołania RegisterClassEx, mam ten zestaw dla tła:

wcex.hbrBackground = (HBRUSH)0;

Oto mój opiekun dla wiadomości WM_PAINT:

 case WM_PAINT:
 {
   hdc = BeginPaint(hWnd, &ps);
   Gdiplus::Graphics graphics(hdc);
   graphics.DrawImage(*m_pBitmap, 0, 0);
   EndPaint(hWnd, &ps);
   break;
 }

Należy pamiętać, że aplikacja jest zawsze zadokowana po lewej stronie ekranu i nie porusza się. Ale to, co znajduje się pod aplikacją, może się zmienić, gdy użytkownik otwiera, zamyka lub przenosi okna pod nią.

Po pierwszym uruchomieniu aplikacji wygląda idealnie. Przezroczyste (i Simi-przezroczyste) części PNG Pokaż doskonale. Ale gdy tło pod aplikacją się zmienia, tło nie aktualizuje się, po prostu pozostaje takie samo od momentu uruchomienia aplikacji. W rzeczywistości WM_PAINT (lub WM_ERASEBKGND nie jest wywoływany, gdy zmienia się tło).

Grałem w to od dłuższego czasu i zbliżyłem się do uzyskania 100% racji, ale nie do końca. Na przykład próbowałem ustawić tło na (HBRUSH) NULL_BRUSH i próbowałem obsługiwać WM_ERASEBKGND.

Co można zrobić, aby okno zostało przemalowane, gdy zawartość pod nim się zmieni?

Author: Tim, 2010-10-19

2 answers

Udało mi się zrobić dokładnie to, co chciałem, używając kodu z części 1 i 2 tej serii: http://code.logos.com/blog/2008/09/displaying_a_splash_screen_with_c_introduction.html

Te posty na blogu mówią o wyświetlaniu ekranu powitalnego w Win32 C++, ale było to prawie identyczne do tego, co musiałem zrobić. Wydaje mi się, że część, której mi brakowało, to to, że zamiast malować PNG do okna za pomocą GDI+, musiałem użyć UpdateLayeredWindow Funkcja z właściwy parametr BLENDFUNCTION. Wkleję poniższą metodę SetSplashImage, która znajduje się w części 2 w linku powyżej:

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);
}
 32
Author: adoss,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2018-08-14 13:57:46

Użyj SetLayeredWindowAttributes, pozwala to ustawić kolor maski, który stanie się przezroczysty, umożliwiając w ten sposób tło.

Http://msdn.microsoft.com/en-us/library/ms633540 (VS. 85). aspx

Będziesz także musiał skonfigurować okno z flagą warstwową, np.

SetWindowLong(hwnd, GWL_EXSTYLE, GetWindowLong(hwnd, GWL_EXSTYLE) | WS_EX_LAYERED);

Potem jest to dość proste:

// Make red pixels transparent:
SetLayeredWindowAttributes(hwnd, RGB(255,0,0), 0, LWA_COLORKEY);

Gdy PNG zawiera półprzezroczyste piksele, które chcesz połączyć z tłem, staje się to bardziej skomplikowane. Możesz spróbować spojrzeć na podejście w tym artykule CodeProject:

Chłodne, półprzezroczyste i ukształtowane okna dialogowe ze standardowymi kontrolkami Dla Windows 2000 i nowszych

 17
Author: Simon Steele,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2010-10-19 16:45:26