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.
http://stackoverflow.com/questions/1842377/double-buffer-common-controls – Flot2011
@ 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. –
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. –