windowHdc = GetDC(hWnd);
HDC secondaryBuffer = CreateCompatibleDC(windowHdc);
HBITMAP map = CreateCompatibleBitmap(windowHdc, width, height);
SelectObject(secondaryBuffer, map);
return secondaryBuffer;
HDC
, полученное из GetDC
или BeginPaint
, не может быть повторно использовано, как отмечено в комментариях.
Однако вы можете повторно использовать растровое изображение памяти (из CreateCompatibleBitmap
) и повторно использовать память постоянного тока (полученную из CreateCompatibleDC
), хотя обычно нет смысла повторно использовать память постоянного тока.
Кроме того, очисткатребуется, чтобы избежать утечки ресурсов.Позвоните ReleaseDC
, когда вы закончите с GetDC
См. Документацию для соответствующих функций деблокирования / удаления.
Сделайте это для простой процедуры рисования:
case WM_PAINT:
{
PAINTSTRUCT ps;
HDC hdc = BeginPaint(hwnd, &ps);
Gdiplus::Graphics gr(hdc);
Gdiplus::Pen testPen(Gdiplus::Color(255, 0, 0), 1.0F);
gr.Clear(Gdiplus::Color::White);
gr.DrawLine(&testPen, 0, 0, 100, 100);
EndPaint(hwnd, &ps);
return 0;
}
Обычно вам больше ничего не нужно делать.Просто позвоните InvalidateRect
в ответ на WM_SIZE
для обновления краски.
Для двойной буферизации или рисования на холсте вы можете создать растровое изображение памяти и использовать его повторно.Если размер окна изменяется, вам нужно вызвать DeleteObject
для старого растрового изображения и создать новое растровое изображение на основе нового размера.Или вы можете создать растровое изображение, которое соответствует наибольшему размеру окна, а затем использовать это растровое изображение для всех размеров окна.
См. Приведенный ниже пример для рисования с двойным буфером (однако повторное использование hbitmap
в этом случае не требуется)
HBITMAP hbitmap = NULL;
void InitPaint(HWND hwnd)
{
HDC hdc = GetDC(hwnd);
//create a bitmap with max size:
int w = GetSystemMetrics(SM_CXFULLSCREEN);
int h = GetSystemMetrics(SM_CYFULLSCREEN);
hbitmap = CreateCompatibleBitmap(hdc, w, h);
ReleaseDC(hwnd, hdc);
}
void cleanup()
{
if (hbitmap)
DeleteObject(hbitmap);
}
...
case WM_PAINT:
{
PAINTSTRUCT ps;
HDC hdc = BeginPaint(hwnd, &ps);
RECT rc; GetClientRect(hwnd, &rc);
int w = rc.right;
int h = rc.bottom;
HDC memdc = CreateCompatibleDC(hdc);
HBITMAP oldbmp = (HBITMAP)SelectObject(memdc, hbitmap);
Gdiplus::Graphics gr(memdc);
Gdiplus::Pen testPen(Gdiplus::Color(255, 0, 0), 1.0F);
gr.Clear(Gdiplus::Color(255, 255, 255));
gr.DrawLine(&testPen, 0, 0, w, h);
BitBlt(hdc, 0, 0, w, h, memdc, 0, 0, SRCCOPY);
//cleanup:
SelectObject(memdc, oldbmp);
DeleteDC(memdc);
EndPaint(hwnd, &ps);
return 0;
}
Резюме:
GetDC
ничего не создает.Он возвращает только ссылку на существующий дескриптор, который используется системой.Когда вы закончите с этой ручкой, отпустите ее.Дальнейшая оптимизация невозможна.
Другие объекты GDI, такие как перо или растровое изображение, могут быть созданы для вашей программы, и их можно использовать повторно.Создание / уничтожение пера занимает всего несколько наносекунд, поэтому обычно не стоит добавлять сложность для хранения этих объектов и отслеживания.
Основная проблема - когда вы рисуете на экране,например, рисование линии.Вы должны поговорить с видеокартой и поговорить с монитором, что занимает некоторое время.Вы можете использовать двойную буферизацию для рисования на растровом изображении, а затем BitBlt
на экране.BitBlt
может быть медленным, в зависимости от системы.
Для анимации используйте двойную буферизацию, если вы видите мерцание.
Для повышения производительности вы можете использовать более новые технологии, такие как Direct2D
Если анимация все еще слишком медленная, рассмотрите возможность использования второго потока для выполнения любых вычислений математического типа (второй поток не должен ссылаться на какие-либодескриптор окна, например HDC
от GetDC
или BeginPaint
)