2012-05-14 13 views
5

Sto utilizzando lo stile di finestra WM_EX_TRANSPARENT su alcune finestre nel tentativo di eseguire il doppio buffer con trasparenza. Tuttavia, sto avendo un problema perché quando faccio InvalidateRect nella finestra genitore, le finestre figlie non vengono ridisegnate.WM_EX_TRANSPARENT non ridisegna le finestre secondarie

È responsabilità della finestra genitore iterare le finestre secondarie e farle ridisegnare se stesse o sto sbagliando? Se è responsabilità della finestra genitore, come posso ottenere tutte le finestre figlio all'interno del rettangolo non valido del genitore?

Ecco un esempio completamente compilabile che illustra il comportamento di cui sto parlando. Puoi vedere che il pulsante scompare quando muovi il mouse sopra la finestra genitore. Il pulsante si ridisegna se fai clic su di esso, ma scompare di nuovo quando tocchi il mouse e torna alla finestra principale.

#include <Windows.h> 

LRESULT CALLBACK WndProc(HWND window, UINT uMsg, WPARAM wParam, LPARAM lParam) { 
    switch (uMsg) { 
    case WM_CREATE: 
     return 0; 

    case WM_MOUSEMOVE: 
     InvalidateRect(window, NULL, true); 

     return 0; 

    case WM_NCDESTROY: 
     PostQuitMessage(0); 
     break; 
    } 

    return DefWindowProc(window, uMsg, wParam, lParam); 
} 

int PASCAL WinMain(HINSTANCE hinst, HINSTANCE, LPSTR, int nShowCmd) { 
    WNDCLASS wc; 
    wc.style   = 0; 
    wc.lpfnWndProc = WndProc; 
    wc.cbClsExtra = 0; 
    wc.cbWndExtra = 0; 
    wc.hInstance  = hinst; 
    wc.hIcon   = NULL; 
    wc.hCursor  = LoadCursor(NULL, IDC_ARROW); 
    wc.hbrBackground = (HBRUSH)(COLOR_WINDOW + 1); 
    wc.lpszMenuName = NULL; 
    wc.lpszClassName = "test_window"; 

    RegisterClass(&wc); 

    HWND wnd = CreateWindowEx(WS_EX_TRANSPARENT, "test_window", "test", WS_CLIPCHILDREN | WS_OVERLAPPEDWINDOW, 50, 50, 400, 400, NULL, NULL, hinst, NULL); 

    ShowWindow(wnd, SW_SHOW); 

    HWND btn = CreateWindowEx(WS_EX_TRANSPARENT, "BUTTON", "button 1", WS_CHILD, 50, 50, 100, 50, wnd, NULL, hinst, NULL); 

    ShowWindow(btn, SW_SHOW); 

    MSG m; 

    while (GetMessage(&m, NULL, 0, 0)) { 
     TranslateMessage(&m); 
     DispatchMessage(&m); 
    } 

    return 0; 
} 

La soluzione finale

è stato quello di fare come la risposta qui sotto suggerito, e poi nel WM_PAINT messaggio della finestra padre inviare un WM_PAINT ad ogni bambino e hanno i figli vernice nel doublebuffer del genitore (non dipingendo nulla in se stesso) e poi ha il genitore BitBlt il suo buffer (che è stato disegnato da solo e poi da ciascuno dei suoi figli che va dal basso verso l'alto dell'ordine Z) nel suo HDC. Ciò consente di disegnare il genitore e il bambino senza sfarfallio e la trasparenza per il bambino. Ecco il programma demo finale siamo arrivati ​​a:

#include <Windows.h> 

// the handle to the single child window 
HWND child; 

// parent's backbuffer so we can use it in the child 
HDC bbuf = 0; 

LRESULT CALLBACK WndProc(HWND window, UINT uMsg, WPARAM wParam, LPARAM lParam) { 
    switch (uMsg) { 
    case WM_CREATE: 
     return 0; 

    case WM_MOUSEMOVE: 
     InvalidateRect(window, NULL, true); 

     return 0; 

    case WM_PAINT: { 
     PAINTSTRUCT ps; 
     POINT mpos; 
     GetCursorPos(&mpos); 
     ScreenToClient(window, &mpos); 

     BeginPaint(window, &ps); 

     // create the backbuffer once 
     bbuf = bbuf ? bbuf : CreateCompatibleDC(ps.hdc); 

     // hardcoded size is the same in the CreateWindowEx call 
     static auto backbmp = CreateCompatibleBitmap(ps.hdc, 400, 400); 

     static auto unused = SelectObject(bbuf, backbmp); 

     POINT points[2] = { 
      { 0, 0 }, 
      { mpos.x, mpos.y } 
     }; 

     // painting into bbuf 
     // give ourselves a white background so we can see the wblack line 
     SelectObject(bbuf, (HBRUSH)GetStockObject(WHITE_BRUSH)); 
     Rectangle(bbuf, 0, 0, 400, 400); 
     SelectObject(bbuf, (HBRUSH)GetStockObject(BLACK_BRUSH)); 
     Polyline(bbuf, points, 2); 

     // get the child to paint itself into our bbuf 
     SendMessage(child, WM_PAINT, 0, 0); 

     // and after the child has drawn, bitblt everything onto the screen 
     BitBlt(ps.hdc, 0, 0, 400, 400, bbuf, 0, 0, SRCCOPY); 

     EndPaint(window, &ps); 

     return 0; 
    } 

    case WM_ERASEBKGND: 
     return 0; 

    case WM_NCDESTROY: 
     PostQuitMessage(0); 
     break; 
    } 

    return DefWindowProc(window, uMsg, wParam, lParam); 
} 

LRESULT CALLBACK ChildWndProc(HWND window, UINT uMsg, WPARAM wParam, LPARAM lParam) { 
    switch (uMsg) { 
    case WM_CREATE: 
     return 0; 

    case WM_PAINT: { 
     PAINTSTRUCT ps; 

     BeginPaint(window, &ps); 

     static auto backbuffer = CreateCompatibleDC(ps.hdc); 
     static auto backbmp = CreateCompatibleBitmap(ps.hdc, 100, 50); 

     static auto unused = SelectObject(backbuffer, backbmp); 

     // copy the parent's stuff into our backbuffer (the parent has already drawn) 
     BitBlt(backbuffer, 0, 0, 100, 50, bbuf, 50, 150, SRCCOPY); 

     RECT r = { 0, 0, 50, 100 }; 

     // draw into our backbuffer 
     SetBkMode(backbuffer, TRANSPARENT); 
     SetTextColor(backbuffer, RGB(255, 0, 0)); 
     DrawText(backbuffer, "hello", 5, &r, DT_NOCLIP | DT_TABSTOP | DT_EXPANDTABS | DT_NOPREFIX); 

     // bitblt our stuff into the parent's backbuffer 
     BitBlt(bbuf, 50, 150, 100, 50, backbuffer, 0, 0, SRCCOPY); 

     EndPaint(window, &ps); 

     return 0; 
    } 

    case WM_ERASEBKGND: 
     return 0; 
    } 

    return DefWindowProc(window, uMsg, wParam, lParam); 
} 

int PASCAL WinMain(HINSTANCE hinst, HINSTANCE, LPSTR, int nShowCmd) { 
    WNDCLASS wc; 
    wc.style   = 0; 
    wc.lpfnWndProc = WndProc; 
    wc.cbClsExtra = 0; 
    wc.cbWndExtra = 0; 
    wc.hInstance  = hinst; 
    wc.hIcon   = NULL; 
    wc.hCursor  = LoadCursor(NULL, IDC_ARROW); 
    wc.hbrBackground = (HBRUSH)(COLOR_WINDOW + 1); 
    wc.lpszMenuName = NULL; 
    wc.lpszClassName = "test_window"; 

    RegisterClass(&wc); 

    wc.style   = 0; 
    wc.lpfnWndProc = ChildWndProc; 
    wc.cbClsExtra = 0; 
    wc.cbWndExtra = 0; 
    wc.hInstance  = hinst; 
    wc.hIcon   = NULL; 
    wc.hCursor  = LoadCursor(NULL, IDC_ARROW); 
    wc.hbrBackground = (HBRUSH)(COLOR_WINDOW + 1); 
    wc.lpszMenuName = NULL; 
    wc.lpszClassName = "transparent_window"; 

    RegisterClass(&wc); 

    HWND wnd = CreateWindowEx(NULL, "test_window", "test", WS_OVERLAPPEDWINDOW | WS_VISIBLE, 50, 50, 400, 400, NULL, NULL, hinst, NULL); 

    child = CreateWindowEx(NULL, "transparent_window", "", WS_VISIBLE | WS_CLIPSIBLINGS | WS_CLIPCHILDREN | WS_CHILD, 50, 150, 100, 50, wnd, NULL, hinst, NULL); 

    MSG m; 

    while (GetMessage(&m, NULL, 0, 0)) { 
     TranslateMessage(&m); 
     DispatchMessage(&m); 
    } 

    return 0; 
} 

Grazie ancora a Johnathon per trascorrere così tanto tempo ad aiutare a calcolare questo fuori.

+0

http://stackoverflow.com/questions/1842377/double-buffer-common-controls – Flot2011

+0

@ Flot2011 'WS_EX_COMPOSITED' fa il proprio doppio buffering e voglio fare il mio. Usarlo impedisce alle finestre del bambino di scomparire, ma sfarfallano davvero male. Puoi provarlo con il mio programma di esempio, fa la stessa cosa. –

+0

Peccato che la tua soluzione non funzioni sui controlli standard. Non posso fare a meno di sentire che c'è una soluzione migliore, ma non l'ho in offerta. –

risposta

2

rimuovere WS_CLIPCHILDREN dallo stile della finestra di Windows padre. Ciò consentirà alla finestra genitore di dipingere sopra i beni immobili della finestra secondaria, quindi la finestra figlio dipenderà in modo efficace da quella durante la sua chiamata vernice. La vernice della finestra genitore viene chiamata per prima, poi tutte le finestre secondarie ricevono il loro nome. Buona fortuna Seth!

+0

Grazie ancora, ho lavorato su questo stupido problema per giorni. –

+0

Non un problema Seth. Felice di poterti aiutare. – johnathon

Problemi correlati