2010-10-19 24 views
39

Ich erstelle, was eine sehr einfache Win32 C++ - Anwendung sein sollte, die nur dazu dient, nur ein halbtransparentes PNG anzuzeigen. Das Fenster sollte kein Chrom haben und die gesamte Opazität sollte im PNG selbst kontrolliert werden.Ein transparentes Fenster in C++ erstellen Win32

Mein Problem ist, dass das Fenster nicht neu erstellt, wenn der Inhalt unter dem Fenster ändert, so dass die transparenten Bereiche des PNG "stecken" mit, was unter dem Fenster war, als die Anwendung gestartet wurde.

Hier ist die Linie, wo ich ein Setup das neue Fenster:

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

Für den Aufruf zu RegisterClassEx, ich habe diesen Satz für den Hintergrund:

wcex.hbrBackground = (HBRUSH)0; 

Hier ist mein Handler für WM_PAINT Nachricht:

Eine Sache zu beachten ist, dass die Anwendung immer links von t angedockt ist er screen und bewegt sich nicht. Aber was sich unterhalb der Anwendung befindet, kann sich ändern, wenn der Benutzer Fenster darunter öffnet, schließt oder bewegt.

Wenn die Anwendung zum ersten Mal gestartet wird, sieht sie perfekt aus. Die transparenten (und ähnlich transparenten) Teile des PNG zeigen sich perfekt. ABER, wenn sich der Hintergrund unter der Anwendung ändert, wird der Hintergrund NICHT aktualisiert, sondern bleibt gleich, wenn die Anwendung gestartet wurde. Tatsächlich wird WM_PAINT (oder WM_ERASEBKGND nicht aufgerufen, wenn sich der Hintergrund ändert).

Ich spiele schon eine ganze Weile damit und bin fast 100% richtig, aber nicht ganz da. Zum Beispiel habe ich versucht, den Hintergrund auf (HBRUSH) NULL_BRUSH zu setzen und ich habe versucht, WM_ERASEBKGND zu behandeln.

Was kann getan werden, um das Fenster neu zu streichen, wenn sich der Inhalt darunter ändert?

+0

SetBkMode und SetBkColor sind die APIs ich verwendet habe, die transparente geordnete Steuerung zu machen. –

Antwort

32

konnte ich genau das tun, was ich mit dem Code aus Teil 1 und Teil 2 dieser Serie wollte: Das http://code.logos.com/blog/2008/09/displaying_a_splash_screen_with_c_introduction.html

In Blogposts wird ein Begrüßungsbildschirm in Win32 C++ angezeigt, der jedoch fast identisch mit dem war, was ich tun musste. Ich glaube, der Teil, den ich vermisste, war, dass ich die PNG nicht nur mit GDI + in das Fenster malen, sondern die Funktion UpdateLayeredWindow mit dem richtigen Parameter BLENDFUNCTION verwenden musste.Ich werde die SetSplashImage Methode unten Paste, die 2 in der Verbindung oben im Teil zu finden ist:

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); 
} 
+0

beste Antwort, unterstützt auch automatische PNG-Alpha-Mischung bei Verwendung mit WIC (Windows Imaging Component) über die COM-Schnittstelle. – dns

+0

Schluss damit, viel Zeit mit AlphaBlend zu verschwenden. Diese Lösung ist wahrscheinlich eine der einfachsten Möglichkeiten, Per-Pixel-Alpha-Blending zu erzielen, besonders wenn Sie das Fenster aktualisieren. – TheBlueNotebook

16

Mit SetLayeredWindowAttributes können Sie eine Maskenfarbe festlegen, die transparent wird und somit den Hintergrund durchlässt.

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

Sie müssen auch Ihre Fenster mit der geschichteten Flagge konfigurieren, zum Beispiel

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

Danach ist es ziemlich einfach:

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

Wenn Ihr PNG enthält semi-transparentes Pixel, die Sie mit dem Hintergrund verschmelzen wollen, dies wird komplizierter. Sie könnten versuchen, bei der Annäherung in diesem Artikel Codeproject suchen:

Cool, Semi-transparent and Shaped Dialogs with Standard Controls for Windows 2000 and Above

+1

Ich habe es versucht und es funktioniert fast. Das Problem ist, dass es einige Bereiche des PNG gibt, die similar transparent sind, und die Farbschlüsselmethode macht nur die Pixel transparent, die 100% Deckkraft des Farbschlüssel-Farbwerts haben. Wenn alles andere fehlschlägt, wird mein Fallback sein, alle halbtransparenten Regionen zu entfernen, aber das würde ich lieber vermeiden. – adoss

+0

Sie können kompliziertere Hacks ausprobieren, wie das in dem Artikel, den ich verlinkt habe, aber im Wesentlichen, sobald Sie ein bereits existierendes Bild mit dem Desktop-Inhalt mischen wollen, werden die Dinge kompliziert. –

+0

Überprüfen Sie die Antwort, die ich gepostet habe. Ich mag diesen Code viel besser als das, was ich in diesem CodeProject Artikel gesehen habe. Nicht nur das, aber ich glaube, was ich gefunden habe, ist die richtige Lösung anstelle eines Hacks. Danke für die Hilfe! – adoss

Verwandte Themen