}
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 — для рисования во фрагментах памяти, и т.д.
Далее: Использование перьев и кистей для рисования на холсте.
Перья и кисти внутри классов
Перевод А. И. Легалова
Англоязычный оригинал находится на сервере компании Reliable Software
Подобно живописцу, Вы нуждаетесь в перьях и кистях, чтобы создать шедевр на вашем холсте. Когда Вы вызываете метод Canvas::Line или Canvas::Rectangle, Windows использует текущие установки пера, чтобы рисовать линии, и текущие установки кисти, чтобы заполнять охватываемые контуры.
Когда объект сопоставляется с Холстом, нельзя забывать освободить его после окончания работы. Это надо делать до тех пор, пока вы не обеспечите такой возможностью вашу программу на языке C++. Используйте только локальные объекты, чьи конструкторы присоединяют, а деструкторы (вызываемые автоматически, при выходе области действия) освобождают объекты (см. страницу «Управление ресурсами» для более детального знакомства с этой методологией). Обратите внимание, что ниже следующие объекты используют HDC (дескрипторы контекстов устройств) в качестве параметры в их конструкторах. Однако, взамен этого, Вы должны просто передать им объект Canvas. Помните, что «Холст» может автоматически приводиться к HDC.
class StockObject {
public:
StockObject(HDC hdc, int type) : _hdc(hdc) {
_hObjOld = SelectObject(_hdc, GetStockObject(type));
}
~StockObject () {
SelectObject(_hdc, _hObjOld);
}
private:
HGDIOBJ _hObjOld;
HDC _hdc;
};
Windows имеет набор предопределенных перьев и кистей. Если Вы хотите использовать их, то достаточно присоединить выбранные перья и кисти к вашему холсту не некоторое время.
class WhitePen : public StockObject {
public:
WhitePen(HDC hdc): StockObject(hdc, WHITE_PEN) {}
};
// example
void Controller::Paint(HWND hwnd) {
PaintCanvas canvas(hwnd);
WhitePen pen(canvas);
canvas.Line(0, 10, 100, 10);
// destructor of WhitePen
// destructor of PaintCanvas
}
Если ваша программа поддерживает использование несколько перьев, отсутствующих в Windows, Вы можете предварительно создать их (например, внедрив их в объект View) и использовать объект PenHolder, для временного присоединения к Холсту.
class Pen {
public:
Pen(COLORREF color) {
_hPen = CreatePen(PS_SOLID, 0, color);
}
~Pen() {
DeleteObject(_hpen);
}
operator HPEN() {
return _hPen;
}
private:
HPEN _hPen;
};
class PenHolder {
public:
PenHolder(HDC hdc, HPEN hPen) : _hdc (hdc) {
_hPenOld = (HPEN)SelectObject (_hdc, hPen);
}
~PenHolder() {
SelectObject(_hdc, _hPenOld);
}
private:
HDC _hdc;
HPEN _hPenOld;
};
class View {
public:
View() : _penGreen (RGB (0, 255, 128)) {}
void Paint(Canvas& canvas) {
PenHolder holder(canvas, _penGreen);
canvas.Line(0, 10, 100, 10);
// destructor of PenHolder
}
private:
Pen _penGreen;
};
И, наконец, если ваша программа нуждается в произвольных цветных перьях, то есть, невозможно предварительно определить всех цветов, в которых вы будете нуждаться, Вы должны использовать цветные перья. Когда Вы определяете автоматический объект ColorPen, его конструктор создает и присоединяет перо. Когда, в конце области действия, вызывается деструктор, он отсоединяет перо и удаляет его.
class ColorPen {
public:
ColorPen(HDC hdc, COLORREF color) : _hdc (hdc) {
_hPen = CreatePen(PS_SOLID, 0, color);
_hPenOld = (HPEN)SelectObject(_hdc, _hPen);
}
~ColorPen() {
SelectObject(_hdc, _hPenOld);
DeleteObject(_hPen);