
- •Режимы рисования, устанавливаемые вызовом функции cdc::SetRop2()
- •Задание 1. Создание объектов контекста устройства, инструментов рисования и демонстрация режимов отображения
- •Создание графических изображений закраской пикселов
- •Задание 2. Цветовая закраска пикселов при создании узоров
- •Подведение итогов
- •Глава 11. Использование функций рисования
- •Функции рисования графических примитивов
- •Рисование прямых и кривых линий
- •Рисование фигур с замкнутым контуром
- •Дополнительные функции рисования класса cdc
- •Задание 1. Демонстрация графических примитивов
Подведение итогов
В этой главе вы ознакомились с объектами контекстов устройств, атрибутами рисования и рисованием точек с помощью функций класса CDC. Кратко изложим основные принципы рассмотренной методики.
Создайте объект контекста устройства. При рисовании с помощью функции OnDraw() класса представления можно использовать объект контекста устройства, передаваемый в функцию. При рисовании с помощью другой функции можно создать экземпляр класса CClientDC, а при рисовании в окне представления, поддерживающем прокрутку — передать объект в функцию CScrollView::OnPrepareDC() до его использования.
Выберите перо для рисования линий и границ фигур с замкнутыми контурами и кисть для закрашивания внутренних областей фигур.
Стандартное перо или кисть выбирается при вызове функции CDC::SelectStockObject().
Можно выбрать перо или кисть, создавая объект класса CPen или CBrush, и вызывая соответствующую функцию для их инициализации, а затем вызвав функцию CDC::SelectObject() для выбора инструмента в объекте контекста устройства. Сохраните предыдущий выбранный объект, возвращенный функцией CDC::SelectObject().
Используйте функции класса CDC для установки любых желаемых атрибутов рисования. К ним относится режим отображения, определяющий единицы измерения и направление изменения значений координат, используемых для рисования.
Нарисуйте изображение, вызывая функции класса CDC, предоставляющего функции для закрашивания отдельных пикселов, рисования прямых или кривых линий и таких фигур, как прямоугольники и эллипсы.
Если созданы и выбраны пользовательское перо или кисть, удалите их из объекта контекста устройства, вызвав функцию SelectObject(), чтобы вернуться к предыдущему перу или кисти.
Глава 11. Использование функций рисования
В этой главе рассматриваются вопросы:
рисование линий разной толщины, цвета и типа;
рисование и заливка замкнутых фигур;
выбор цвета с помощью стандартного диалогового окна;
создание иерархии классов графических объектов.
Функции рисования графических примитивов
Класс CDC содержит набор функций рисования прямых и кривых линий, а также геометрических фигур. Набор фигур, создаваемый функциями рисования, составляет графические примитивы, с помощью которых можно создать изображение и узор любой сложности. Как использовать функции рисования графических примитивов мы рассмотрим в этом параграфе.
Рисование прямых и кривых линий
Многие функции рисования используют понятие текущей позиции объекта контекста устройства. Текущая позиция — это координаты точки, которые получены в результате выполнения последней операции рисования. Текущую позицию можно установить с помощью функции CDC::MoveTo() и получить вызовом функции CDC::GetCurrentPosition(). Функция CDC::MoveTo() имеет такие прототипы:
CPoint CDC::MoveTo( int x, int y ); CPoint CDC::MoveTo( POINT point );
где параметры определяют координаты точки, в которую перемещается курсор, а возвращаемое значение определяет координаты предыдущей позиции в виде объекта класса CPoint.
Прототип функции CDC::GetCurrentPosition() имеет следующий вид:
CPoint CDC::GetCurrentPosition() const;
Функция возвращает значение текущей позиции в логических координатах.
Чтобы нарисовать прямую линию необходимо предварительно переместиться в начальную ее точку, задав координаты этой точки с помощью функции CDC::MoveTo(). Затем, указав координаты конечной точки линии, получить саму линию с помощью функции, имеющей такие прототипы:
BOOL CDC::LineTo( int x, int y ); BOOL CDC::LineTo( POINT point );
Параметрами функции CDC::LineTo() являются горизонтальная и вертикальная координаты новой точки или структура типа POINT, поля которой — те же координаты.
Например, следующий фрагмент программы рисует линию от точки (5, 15) до точки (25,40).
pDC->MoveTo (5, 15); pDC-> LineTo (25, 40);
Функция CDC::LineTo() рисует линию из текущей позиции до конечной точки, заданной переданными в нее аргументами. Функция CDC::LineTo() также изменяет текущую позицию, чтобы задать конечную точку. Таким образом, при рисовании последовательности соединенных между собой линий, необходимо вызвать функцию CDC::MoveTo() только перед первым вызовом функции CDC::LineTo(). Например, следующий фрагмент программы рисует последовательность соединенных линий, формирующих букву "W".
pDc->MoveTo (50, 50); pDc->LineTo (100, 150); pDc->LineTo (150, 100); pDc->LineTo (200, 150); pDc->LineTo (250, 50);
Если объект контекста устройства создается впервые, то текущая позиция имеет логические координаты (0, 0).
Последовательно соединенные отрезки линий или, другими словами, ломаная линия может быть отображена с помощью одной функции CDC::Polyline(), которой в качестве аргументов передают указатель на массив точек, каждая из которых представлена структурой POINT или объектом класса CPoint. Указанный массив координат определяет точки соединения отрезков линии. Второй параметр определяет количество этих точек. Прототип функции CDC::Polyline()объявлен таким образом:
BOOL CDC::Polyline( LPPOINT lpPoints, int nCount );
Например, следующий фрагмент программы рисует такую же последовательность соединенных линий, как в предыдущем примере.
POINT lpPoints [5] lpPoints [0].x = 50; lpPoints [0].y = 50; lpPoints [1].x = 100; lpPoints [1].y = 150; lpPoints [2].x = 150; lpPoints [2].y = 100; lpPoints [3].x = 200; lpPoints [3].y = 150; lpPoints [4].x = 250; lpPoints [4].y = 50; pDC->Polyline (lpPoints, 5);
Функция CDC::Polyline() никогда не переустанавливает текущую позицию. Функция CDC::PolylineTo() наоборот, рисует линию от текущей позиции до первой указанной точки и перемещает текущую позицию в последнюю заданную точку.
Можно вызвать функцию CDC::PolyPolyline() для рисования нескольких ломаных в одной операции. Подобно функции CDC::Polyline() функция CDC::PolyPolyline() не изменяет установки текущей позиции. Прототип этой функции определен так:
BOOL CDC::PolyPolyline( const POINT* lpPoints, const DWORD* lpPolyPoints, int nCount );
Функция CDC::PolyPolyline() имеет такие параметры: lpPoints — указатель на массив точек, которые являются вершинами ломаной линии, каждая точка представлена горизонтальной и вертикальной координатой, lpPolyPoints — указатель на массив переменных, определяющих количество точек массива lpPoints для соответствующего многоугольника, nCount — общее количество элементов массива lpPolyPoints.
Наконец, если любая из этих функций используется для рисования фигуры с замкнутым контуром, то фигура не заливается цветом автоматически, в отличие от функций рисования замкнутых фигур.
Кривые линии можно получить с помощью функций класса CDC, которые рисуют дуги эллипсов и лекало (сплайн Безье). Кривые линии, являющиеся сегментами эллипсов, рисуют с помощью функции CDC::Arc(), прототипы которой представлены ниже:
BOOL CDC::Arc( int x1, int y1, int x2, int y2, int x3, int y3, int x4, int y4 ); BOOL CDC::Arc( LPCRECT lpRect, POINT ptStart, POINT ptEnd );
Параметры имеют следующий смысл: x1, y1 — координаты левого верхнего угла прямоугольника, ограничивающего эллипс, сегментом которого является дуга; x2, y2 — координаты правого нижнего угла этого же прямоугольника; x3, y3 — координаты стартовой точки дуги; x4, y4 — координаты конечной точки дуги. Для второго прототипа задаются параметры: lpRect — указатель на объект класса CRect, определяющий прямоугольник, ограничивающий эллипс; ptStart — указатель на структуру типа POINT, определяющий координаты стартовой точки дуги, ptEnd — указатель на структуру типа POINT, определяющий конечную точку дуги.
Функция CDC::Arc() никогда не использует и не корректирует текущую позицию. Указанная начальная точка необязательно должна принадлежать эллипсу. Она может быть где-либо на линии, проходящей через центр ограничивающего прямоугольника и начальную точку на эллипсе. Это справедливо и для задания конечной точки. Координаты, заданные пользователем для рисования дуги, показаны на рис. 11.1.
Рис. 11.1. Координаты, переданные в функцию CDC::Arc()
По умолчанию дуга рисуется из начальной точки в конечную против часовой стрелки. Для изменения направления рисования вызовите функцию CDC::SetArcDirection(). Прототип функции CDC::SetArcDirection() определен таким образом:
int CDC::SetArcDirection( int nArcDirection );
где параметр nArcDirection определяет направление рисование дуги и может принимать такие значения: AD_COUNTERCLOCKWISE — против часовой стрелке, AD_CLOCKWISE — по часовой стрелке.
Получить текущее направление рисование дуги можно, вызвав функцию CDC::GetArcDirection().
Можно нарисовать кривую лекала, которая не является сегментом эллипса, вызывая функцию CDC::PolyBezier(). Функция имеет такой прототип:
BOOL PolyBezier( const POINT* lpPoints, int nCount );
Параметры функции имеют такой смысл: lpPoints — указатель на массив структур POINT, nCount — количество структур в массиве.
Рис. 11.2. Кривая Безье, состоящая из одиночного сплайна
Функция CDC::PolyBezier() рисует последовательность соединенных кривых, называемых сплайном Безье. Рассмотрим рисование одиночного сплайна (рис. 11.2). Массив, передаваемый в первом параметре, содержит четыре структуры POINT с координатами точек кривой: первая — начальная точка, вторая и третья — управляющие, задающие форму кривой, четвертая — последняя точка кривой.
Следующий фрагмент программы рисует одиночный сплайн, отображенный на рис. 11.2.
// Рисование кривой, состоящей из одного сплайна: POINT lpPoints [4]; lpPoints [0].x = 25; lpPoints [0].y = 25; lpPoints [1].x = 35; lpPoints [1].y = 170; lpPoints [2].x = 130; lpPoints [2].y = 20; lpPoints [3].x = 150; lpPoints [3].y = 150; pDC-> PolyBezier (lpPoints, 4);
Рис. 11.3. Кривая Безье, состоящая из двух соединенных сплайнов
Для наращивания кривой другим сплайном нужно прибавить к массиву только три дополнительные точки: две — для управления точками нового сплайна и одну — в качестве последней точки нового сплайна. Начальная точка нового сплайна совпадает с последней точкой предыдущего. На рис. 11.3 показана кривая Безье, состоящая из двух соединенных сплайнов. Точки Points[0] и Points[3] являются точками начала и конца первого сплайна, точки Points[3] и Points[6] определяют начало и конец второго сплайна. Точка Points[1] управляет формой первого сплайна, точка Points[5] — второго сплайна. Точки Points[2] и Points[4] являются управляющими для обоих сплайнов одновременно и изменяют форму всей кривой. Чтобы переход от одного сплайна к другому был плавным, необходимо, чтобы последняя управляющая точка первого сплайна, конечная точка первого сплайна, являющаяся начальной точкой второго, и первая управляющая точка второго сплайна лежали на одной прямой. Например, на рис. 11.3 переход плавный потому, что точки Points[2], Points[3] и Points[4] лежат на одной прямой.
Следующий фрагмент программы рисует кривую (рис. 11.3), состоящую из двух соединенных сплайнов (первый такой же, как в предыдущем примере).
// Рисование кривой, состоящей из двух сплайнов: POINT lpPoints [7]; lpPoints [0].x = 25; lpPoints [0].y = 25; lpPoints [1].x = 35; lpPoints [1].y = 170; lpPoints [2].x = 130; lpPoints [2].y = 20; lpPoints [3].x = 150; lpPoints [3].y = 150; lpPoints [4].x = 170; lpPoints [4].y = 280; lpPoints [5].x = 250; lpPoints [5].y = 115; lpPoints [6].x = 250; lpPoints [6].y = 225; pDC->PolyBezier (lpPoints, 7);
Вообще, количество элементов типа POINT в массиве lpPoints , присваиваемое параметру nCount, должно быть на единицу больше трехкратного количества требуемых сплайнов. Поскольку последняя точка данного сплайна используется как начальная точка следующего, отдельные сплайны, нарисованные с помощью функции CDC::PolyBeizer(), всегда соединены. Функция PolyBezier() класса CDC, в отличие от функции CDC::PolyBezierTo(), никогда не использует и не изменяет текущую позицию.