SoftCraft
разноликое программирование

Top.Mail.Ru

Перья и кисти внутри классов


Рисование перьями и раскрашивание кистями

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

Англоязычный оригинал находится на сервере компании 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);
    }
private:
    HDC     _hdc;
    HPEN    _hPen;
    HPEN    _hPenOld;
};

Точно таким же способом Вы можете работать с кистями (кистей, поддерживаемых Windows, гораздо больше, чем перьев). В качестве примера, ниже дается определение ColorBrush.


class ColorBrush
{
public:
    ColorBrush (HDC hdc, COLORREF color)
        : _hdc (hdc)
    {
        _hBrush = CreateSolidBrush (color);
        _hBrushOld = (HBRUSH)SelectObject (_hdc, _hBrush);
    }
    ~ColorBrush ()
    {
        SelectObject (_hdc, _hBrushOld);
        DeleteObject (_hBrush);
    }
private:
    HDC     _hdc;
    HBRUSH  _hBrush;
    HBRUSH  _hBrushOld;
};

Как всегда, мы пощряем Ваши собственные эксперименты.

Далее: совершенно иная тема - "Потоки".