Podwójne buforowanie rysowania

Autor podstrony: Krzysztof Zajączkowski

Stronę tą wyświetlono już: 3013 razy

Wstęp

Ci z pośród Was, którzy przerobili projekt do tego miejsca zapewne zauważyli, że przy rysowaniu elementy programu mrugają dość nieprzyjemnie. Wyeliminowanie tego nieprzyjemnego zjawiska wymaga czegoś co nazywa się podwójnym buforowaniem rysowania. Co to oznacza? Oznacza to to, że trzeba utworzyć dodatkowy kontekst urządzenia HDC oraz uchwyt bitmapy HBITMAP, który za pomocą funkcji SelectObject powinien zostać przypisany do pomocniczego kontekstu urządzenia. Teraz wszystkie operacje rysowania muszą być wykonywane na kontekście urządzenia pomocniczego a następnie całość już odrysowanego obszaru powinna zostać przerysowana na kontekst urządzenia związany z samym oknem programu.

Innymi słowy, najpierw odrysowuję obszar na bitmapie, później bitmapę przerysowuję do okna programu.

Implementacja podwójnego buforowania

W kodzie programu w pliku winmain.cpp w funkcji WinMain należy usunąć następującą linijkę kodu:

wnd.hbrBackground = (HBRUSH)GetStockColor(BLACK_BRUSH);

Powyższa linijka zarysowywała tło okna rysowania na czarno, ten jednak efekt nas nie interesuje a interesuje nas jedynie to aby program w ogóle nie zamalowywał tła.

W funkcji procedury okna WndDrawingProc należy dodać trzy następujące nowe zmienne:

static HBITMAP hBmpBk; // bitmapa podwójnego buforowania static HDC mem; // uchwyt kontekstu podwójnego buforowania związanego z hBmpBk static RECT wndRect; // wymiary obszaru okna

W komunikacie WM_CREATE należy dodać linijkę kodu, w którym utworzony zostanie pomocniczy kontekst urządzenia:

mem = CreateCompatibleDC(GetDC(NULL)); // tworzenie kompatybilnego z systemem kontekstu urządzenia

I dodajemy obsługę komunikatu WM_SIZE, która będzie wyglądała następująco:

case WM_SIZE: { SetRect(&wndRect, 0, 0, LOWORD(lParam), HIWORD(lParam)); // pobieranie wymiarów okna DeleteObject(hBmpBk); // usuwanie bitmapy hBmpBk = CreateCompatibleBitmap(GetDC(NULL), wndRect.right, wndRect.bottom); // tworzenie kompatybilnej bitmapy SelectObject(mem, hBmpBk); // przypisanie bitmapy do kontekstu urządzenia } break;

Ostatnim krokiem do wyeliminowania mrugania rysowanych obiektów w oknie programu jest zmiana kodu w komunikacie WM_PAINT:

case WM_PAINT: { PAINTSTRUCT ps; HDC hdc = BeginPaint(hWndDraw, &ps); FillRect(mem, &wndRect, (HBRUSH)GetStockObject(BLACK_BRUSH)); // zamalowanie bitmapy na czarno SetBkMode(mem, TRANSPARENT); for(std::vector<i_dr_obj*>::iterator i = tObj.begin(); i < tObj.end(); i++){ (*i)->Draw(mem, tPen, tBrush); // rysowanie dodanych obiektów } if(st == state::sel){ SelObjAct.WmPaint(mem); } if(obj){ obj->Draw(mem, tPen, tBrush); // rysowanie dodawanego obiektu } BitBlt(hdc, 0, 0, wndRect.right, wndRect.bottom, mem, 0, 0, SRCCOPY); // przerysowanie bitmapy do okna EndPaint(hWndDraw, &ps); } break;

Jak wynika z powyższego kodu, teraz wszystko jest rysowane na kontekście urządzenia mem a nie jak poprzednio na hdc. Dopiero na samym końcu funkcją BitBlt przerysowany został obszar bitmapy przypisanej do mem do kontekstu urządzenia hdc okna programu.

Propozycje książek

Załączniki:

Program Rysowanie w wersji z strony tutaj