GDI + двойная буферизация в C ++ - PullRequest
7 голосов
/ 19 марта 2010

Я давно ничего не писал с GDI (и никогда с GDI +), и я просто работаю над забавным проектом, но я не могу понять, как создать двойной буфер GDI +

void DrawStuff(HWND hWnd) {
    HDC          hdc;
    HDC          hdcBuffer;
    PAINTSTRUCT  ps;
    hdc = BeginPaint(hWnd, &ps);
    hdcBuffer = CreateCompatibleDC(hdc);
    Graphics graphics(hdc);
    graphics.Clear(Color::Black);

    // drawing stuff, i.e. bunnies:

    Image bunny(L"bunny.gif");
    graphics.DrawImage(&bunny, 0, 0, bunny.GetWidth(), bunny.GetHeight());  

    BitBlt(hdc, 0,0, WIDTH , HEIGHT, hdcBuffer, 0,0, SRCCOPY);
    EndPaint(hWnd, &ps);
}

Выше работает (все отлично), но мерцает. Если я изменю Graphics graphics(hdc); на Graphics graphics(hdcBuffer);, я ничего не вижу (хотя я должен был побитовать буфер -> hWnd hdc внизу).

Мой конвейер сообщений настроен правильно (WM_PAINT вызывает DrawStuff), и я заставляю сообщение WM_PAINT каждый цикл программы, вызывая RedrawWindow(window, NULL, NULL, RDW_ERASE | RDW_INVALIDATE | RDW_UPDATENOW);

Я, наверное, иду по неправильному пути, есть идеи? Документация MSDN в лучшем случае загадочна.

Ответы [ 3 ]

7 голосов
/ 19 марта 2010

CreateCompatibleDC(hdc) создает DC с монохромным растровым изображением 1x1 пикселей в качестве поверхности рисования. Вам также нужно CreateCompatibleBitmap и выбрать это растровое изображение в hdcBuffer, если вы хотите, чтобы поверхность рисования была больше.

Edit:

Мерцание вызывается WM_ERASEBKGND, когда вы делаете это

hdc = BeginPaint(hWnd, &ps);

Внутри вызова BeginPaint Windows отправляет вашему WndProc сообщение WM_ERASEBKGND , если считает, что фон необходимо перерисовать, если вы не обрабатываете это сообщение, то DefWindowProc обрабатывает его, заполняя прямоугольник рисования. с вашей классовой кистью, чтобы избежать мерцания, вы должны обработать ее и вернуть TRUE.

case WM_ERASEBKGND:
   return TRUE; // tell Windows that we handled it. (but don't actually draw anything)

Windows считает, что ваш фон должен быть удален, потому что вы говорите, что он должен, это то, что означает RDW_ERASE, так что вы, вероятно, должны исключить это из своего RedrawWindow вызова

2 голосов
/ 13 декабря 2012

Вы можете попробовать следующим образом ...

void DrawAll(CDC *pDC)
{
    CRect rect;
    GetClientRect(&rect);

    Bitmap *pMemBitmap = new Bitmap(rect.Width(), rect.Height());

    Graphics* pMemGraphics = Graphics::FromImage(pMemBitmap);

    Graphics graphics(pDC->m_hDC);

    // use pMemGraphics  do something....

    Status status;  
    if ((status = graphics.DrawImage(pMemBitmap, 0, 0)) !=Ok)
    {
        //some error
    }

   delete pMemGraphics;
}
1 голос
/ 19 марта 2010

Вы обрабатываете WM_ERASEBKGND? Я полагаю, что он вызывается прямо перед WM_PAINT и обычно скрывает цвет фона окна, чего вы, вероятно, не хотите.

...