2010-10-19 30 views
39

Sto creando quella che dovrebbe essere una semplice applicazione Win32 C++ che ha l'unico scopo di visualizzare SOLO un PNG semitrasparente. La finestra non dovrebbe avere alcun cromo e tutta l'opacità dovrebbe essere controllata nel PNG stesso.Creazione di una finestra trasparente in C++ Win32

Il mio problema è che la finestra non viene ridisegnata quando il contenuto sotto la finestra cambia, quindi le aree trasparenti del PNG sono "bloccate" con quello che era sotto la finestra quando l'applicazione è stata inizialmente avviata.

Ecco la linea dove ho messa a punto la nuova finestra:

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

Per la chiamata a RegisterClassEx, ho questo set per lo sfondo:

wcex.hbrBackground = (HBRUSH)0; 

Ecco il mio gestore per il messaggio WM_PAINT:

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

una cosa da notare è che l'applicazione è sempre ancorata a sinistra del t si scherma e non si muove. Ma ciò che è sotto l'applicazione può cambiare quando l'utente apre, chiude o sposta finestre sotto di esso.

All'avvio, l'applicazione sembra perfetta. Le parti trasparenti (e semitrasparenti) del PNG mostrano perfettamente. MA, quando lo sfondo sotto l'applicazione cambia, lo sfondo NON si aggiorna, rimane solo lo stesso da quando l'applicazione è stata avviata per la prima volta. Infatti, WM_PAINT (o WM_ERASEBKGND non viene chiamato quando lo sfondo cambia).

Ho giocato con questo per un po 'e sono arrivato a ottenere il 100% giusto, ma non proprio lì. Ad esempio, ho provato a impostare lo sfondo su (HBRUSH) NULL_BRUSH e ho provato a gestire WM_ERASEBKGND.

Cosa è possibile fare per ridisegnare la finestra quando cambia il contenuto sottostante?

+0

SetBkMode e SetBkColor sono le API che ho usato per fare il controllo padre trasparente. –

risposta

32

ero in grado di fare esattamente quello che volevo, utilizzando il codice dalla Parte 1 e Parte 2 di questa serie: http://code.logos.com/blog/2008/09/displaying_a_splash_screen_with_c_introduction.html

Coloro i post del blog stanno parlando della visualizzazione di una schermata iniziale in C++ Win32, ma era quasi identica a ciò che dovevo fare. Credo che la parte che mi mancava era che invece di dipingere semplicemente il PNG alla finestra usando GDI +, avevo bisogno di usare la funzione UpdateLayeredWindow con il parametro BLENDFUNCTION corretto.Io incollo il metodo SetSplashImage di sotto, che si trova nella parte 2 nel link qui sopra:

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

risposta migliore, supporta anche la combinazione automatica alpha PNG quando utilizzata con WIC (Windows Imaging Component) tramite l'interfaccia COM. – dns

+0

Finito per perdere un sacco di tempo con AlphaBlend. Questa soluzione è probabilmente uno dei modi più semplici per ottenere la fusione alfa Per-Pixel, specialmente quando si aggiorna la finestra. – TheBlueNotebook

16

Usa SetLayeredWindowAttributes, questo consente di impostare un colore maschera che diventerà trasparente, consentendo così lo sfondo.

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

Sarà inoltre necessario configurare la finestra con la bandiera a strati, per esempio

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

Dopo di che è abbastanza semplice:

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

Quando il PNG contiene pixel semitrasparenti che si desidera fondersi con lo sfondo, questo diventa più complicato. Si potrebbe provare a guardare l'approccio in questo articolo CodeProject:

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

+1

Ho provato questo e QUASI funziona. Il problema è che ci sono alcune aree del PNG che sono simil-trasparenti, e il metodo dei tasti colorati rende i pixel che sono al 100% opacità del valore del colore della chiave di colore trasparente. Se tutto il resto fallisce, il mio fallback sarà di rimuovere tutte le regioni semi-trasparenti, ma preferirei davvero evitare di farlo. – adoss

+0

È possibile provare hack più complicati come quello nell'articolo che ho collegato, ma sostanzialmente non appena si cerca di fondere un'immagine preesistente con i contenuti del desktop, le cose iniziano a complicarsi. –

+0

Controlla la risposta che ho postato. Mi piace quel codice molto meglio di quello che vedevo in questo articolo CodeProject. Non solo, ma credo che quello che ho trovato sia la soluzione giusta invece di un trucco. Grazie per l'aiuto! – adoss

Problemi correlati