2012-05-14 11 views
5

Używam stylu okna WM_EX_TRANSPARENT w niektórych oknach, próbując wykonać podwójne buforowanie z przezroczystością. Jednak mam problem, ponieważ gdy wykonuję InvalidateRect w oknie nadrzędnym, okna podrzędne nie są przerysowywane.WM_EX_TRANSPARENT nie odświeża okien potomnych

Czy zadaniem okna nadrzędnego jest powtarzanie okien potomnych i nakłanianie ich do odświeżania się, czy też robię to źle? Jeśli jest to odpowiedzialność okna nadrzędnego, w jaki sposób mogę uzyskać wszystkie okna podrzędne w niepoprawnym prostokącie elementu nadrzędnego?

Oto w pełni kompilowany przykład ilustrujący zachowanie, o którym mówię. Możesz zobaczyć, że przycisk znika po przesunięciu wskaźnika myszy nad okno nadrzędne. Przycisk odrysowuje się samoczynnie po kliknięciu, ale znika po ponownym kliknięciu myszką i powrocie do okna nadrzędnego.

#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; 
} 

Ostateczne rozwiązanie

było zrobić jako odpowiedź poniżej zasugerował, a następnie w oknie macierzystej WM_PAINT wiadomość Wyślij WM_PAINT do każdego dziecka i mieć dzieci farby do DoubleBuffer rodzica (nie maluje niczego w sobie), a następnie ma rodzica BitBlt jego bufor (który został wciągnięty w siebie, a następnie przez każde z jego dzieci, przechodząc od dołu do góry kolejności Z) do jego HDC. Pozwala to na rysowanie bez migotania w rodzica i dziecku oraz przezroczystość dla dziecka. Oto końcowy program demo dotarliśmy:

#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; 
} 

Dzięki ponownie do Johnathon spędzania tyle czasu pomaga mi zrozumieć to.

+0

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

+0

@ Flot2011 'WS_EX_COMPOSITED' robi własne podwójne buforowanie i chcę zrobić własne. Używanie go sprawia, że ​​okna podrzędne nie znikają, ale migoczą bardzo źle. Możesz spróbować tego z moim programem przykładowym, robi to samo. –

+0

Szkoda, że ​​Twoje rozwiązanie nie działa w przypadku standardowych elementów sterujących. Nie mogę pomóc, ale czuję, że jest lepsze rozwiązanie, ale nie mam go w ofercie. –

Odpowiedz

2

usuń WS_CLIPCHILDREN ze swojego stylu okna nadrzędnego. Umożliwi to okienko nadrzędne na pomalowanie nieruchomości okna podrzędnego, wówczas okienko podrzędne będzie skutecznie malowało to podczas wywoływania farby. Najpierw jest wywoływana farba okna nadrzędnego, a następnie okna potomne otrzymują nazwę. Powodzenia Seth!

+0

Jeszcze raz dziękuję, pracuję nad tym głupim problemem od wielu dni. –

+0

Nie ma problemu Seth. Cieszę się, że mogłem ci pomóc. – johnathon

Powiązane problemy