Рисование в DC. Как избежать ошибок.


Данная статья не может претендовать на полноту раскрытия принципов рисования в среде Microsoft Windows, она создана в помощь тем, кто делает свои первые шаги в этой области, с целью обратить внимание на основные моменты и предотвратить возможные (наиболее часто встречающиеся) ошибки. Примеры кода будут представлены в двух вариантах: с использованием WinAPI и MFC.

1. Получение DC (Контекста устройства)

Рисование в Windows осуществляется в контексте устройства (DC). Существуют 4 типа DC: Display, Printer, Memory (Compatible DC) и Information. Первые 3 используются для рисования, Information DC – для получения информации об устройстве. В данной статье будет рассматриваться Display DC (обращение с Memory DC будет рассмотрено в следующей статье, которая сейчас в подготовке), а обращение с Printer DC – большая отдельная тема, которую может быть кто-нибудь из участников осветит здесь на форуме. :)

Итак, нам требуется в некотором окне нарисовать нечто свое собственное, картинку, график, текст и т.д. Первым делом необходимо получить контекст для рисования. Для этого в WinAPI применяются следующие методы:

WinAPI
Цитата
// Получить DC клиентской области окна по его хэндлу
HDC GetDC(HWND hWnd);

// Получить DC всего окна (включая его заголовок, меню, скроллбары и т.д.) по его хэндлу
HDC GetWindowDC (HWND hWnd);

// Освободить DC, ранее полученный по GetDC или GetWindowDC
int ReleaseDC (HWND hWnd, HDC hDC);


В MFC классом «оберткой» для DC служит класс CDC. Для получения объекта CDC какого либо окна, в классе CWnd существуют следующие методы:

MFC
Цитата
// Получить DC клиентской области окна
CDC *CWnd:: GetDC ();

// Получить DC всего окна (включая его заголовок, меню, скроллбары и т.д.)
CDC *CWnd:: GetWindowDC ();

// Освободить DC, ранее полученный по GetDC или GetWindowDC
int  CWnd:: ReleaseDC (HWND hWnd, HDC hDC);


Из приведенных методов получения DC наиболее часто используется GetDC, т.к. обычно рисование происходит в клиентской части.


ВАЖНО: Любой DC, полученный по GetDC или GetWindowDC должен быть потом освобожден через вызов ReleaseDC. В противном случае происходят утечки ресурсов GDI, что при долгом времени работы програмы неизбежно приведет к глюкам при рисовании. Также, надо отметить, что ReleaseDC должно вызываться только для DC, полученных по GetDC или GetWindowDC.


Схема получения – освобождения DC

WinAPI

// hWnd - хэндл окна, DC которого нам необходим

// Получаем DC 
HDC hDC = ::GetDC (hWnd);

// Здесь рисуем, используя полученный DC
// …

// Освобождаем DC
::ReleaseDC (hWnd, hDC);


MFC
// m_Button1 - член класса, объект типа CButton
CDC *pDC = m_Button1.GetDC();

// Здесь рисуем, используя полученный DC
// …

// Освобождаем DC
m_Button1.ReleaseDC(pDC);

 
« Предыдущая статья   Следующая статья »