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?
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);
}
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:
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