Обертка для контекста устройств

We use cookies. Read the Privacy and Cookie Policy

Обертка для контекста устройств

Холст или контекст устройств Windows

Перевод А. И. Легалова

Англоязычный оригинал находится на сервере компании Reliable Software

Чтобы раукрашивать, рисовать или печатать в окне, Вам необходим контекст устройств (device context или, кратко, DC). DC — это ресурс, который заимствуется у Windows и, как предполагается, возвращается сразу же после того, как вы сделаете свою работу. Отсюда и берет корни объект Canvas (Холст). Конструктор Холста получает DC, а деструктор освобождает его. Важно то, что Вы создаете объекты Canvas как автоматические (стековые) переменные. Это гарантирует, что, когда программа выйдет из локальной области (контекста), всегда вызовется их деструктор, в которой определены ресурсы (предлагаемый класс является примером более общей методологии Управления ресурсами). Типичное использование объекта Canvas демонстрируется следующем кодом (вы его уже видели в программе Generic):

void Controller::Paint() {

 // prepare the canvas and let View do the rest

 PaintCanvas canvas(_hwnd);

 _view.Paint(canvas, _model);

 // Notice: The destructor of PaintCanvas called automatically!

}

Различные типы Холста совместно используют общего предка — класс Canvas. Обратите внимание, что конструктор Холста защищен. Фактически, Вы не можете сформировать объект этого класса. Однако, наследующие классы открыты, чтобы обеспечить доступ к их собственным конструкторам. Между прочим, Вы можете осуществлять добавление новых методов к Холсту, по мере возникновения такой потребности.

class Canvas {

public:

 // operator cast to HDC

 // (used when passing Canvas to Windows API)

 operator HDC() { return _hdc; }

 void Point(int x, int y, COLORREF color) {

  ::SetPixel(_hdc, x, y, color);

 }

 void MoveTo(int x, int y) {

  ::MoveToEx(_hdc, x, y, 0);

 }

 void Line(int x1, int y1, int x2, int y2 ) {

  MoveToEx(_hdc, x1, y1, 0);

  LineTo(_hdc, x2, y2);

 }

 void Rectangle(int left, int top, int right, int bottom) {

  // draw rectangle using current pen

  // and fill it using current brush

  ::Rectangle(_hdc, left, top, right, bottom);

 }

 void GetTextSize(int& cxChar, int& cyChar) {

  TEXTMETRIC tm;

  GetTextMetrics(_hdc, &tm);

  cxChar = tm.tmAveCharWidth;

  cyChar = tm.tmHeight + tm.tmExternalLeading;

 }

 void Text(int x, int y, char const * buf, int cBuf) {

  ::TextOut(_hdc, x, y, buf, cbuf);

 }

 void Char(int x, int y, char c) {

  TextOut(_hdc, x, y, &c, 1);

 }

 void SelectObject(void* pObj) {

  ::SelectObject(_hdc, pobj);

 }

protected:

 Canvas(HDC hdc): _hdc(hdc) {}

 HDC _hdc;

};

В ответ на сообщение WM_PAINT нужно создать объект PaintCanvas. Обратите внимание на способ получения и освобождения DC объектом PaintCanvas.

class PaintCanvas: public Canvas {

public:

 // Constructor obtains the DC

 PaintCanvas(HWND hwnd) : Canvas(BeginPaint(hwnd, &_paint)), _hwnd(hwnd) {}

 // Destructor releases the DC

 ~PaintCanvas() {

  EndPaint(_hwnd, &_paint);

 }

protected:

 PAINTSTRUCT _paint;

 HWND _hwnd;

};

Другой важный пример — класс UpdateCanvas, который используется для графических операций вне контекста обработки сообщения WM_PAINT. Конечно, ваша программа может всегда инициировать перерисовку, вызывая InvalidateRect, но во многих случаях это было бы массовым убийством. Если ваша программа осуществляет перерисовку новых объектов, когда они обрабатываются или в ответ на действия пользователя, Вы можете модифицировать окно, используя UpdateCanvas.

class UpdateCanvas: public Canvas {

public:

 UpdateCanvas(HWND hwnd) : Canvas(GetDC(hwnd)), _hwnd(hwnd) {}

 ~UpdateCanvas() {

  ReleaseDC(_hwnd, _hdc);

 }

protected:

 HWND _hwnd;

};

Можно создать и другие типы Холста: DrawItemCanvas используется для рисования элементов управления их владельцем, MemCanvas — для рисования во фрагментах памяти, и т.д.

Далее: Использование перьев и кистей для рисования на холсте.