Podwójne buforowanie rysowania

Stronę tą wyświetlono już: 286 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:

Listing 1
  1. 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:

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

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

Listing 3
  1. 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:

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

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

Listing 5
  1. case WM_PAINT:
  2. {
  3. PAINTSTRUCT ps;
  4. HDC hdc = BeginPaint(hWndDraw, &ps);
  5. FillRect(mem, &wndRect, (HBRUSH)GetStockObject(BLACK_BRUSH)); // zamalowanie bitmapy na czarno
  6. SetBkMode(mem, TRANSPARENT);
  7. for(std::vector<i_dr_obj*>::iterator i = tObj.begin(); i < tObj.end(); i++){
  8. (*i)->Draw(mem, tPen, tBrush); // rysowanie dodanych obiektów
  9. }
  10. if(st == state::sel){
  11. SelObjAct.WmPaint(mem);
  12. }
  13. if(obj){
  14. obj->Draw(mem, tPen, tBrush); // rysowanie dodawanego obiektu
  15. }
  16. BitBlt(hdc, 0, 0, wndRect.right, wndRect.bottom, mem, 0, 0, SRCCOPY); // przerysowanie bitmapy do okna
  17. EndPaint(hWndDraw, &ps);
  18. }
  19. 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.

Załączniki:

Program Rysowanie w wersji z strony tutaj

Komentarze