Добавил:
Upload Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:

КР по ОАиП / Учебное пособие Батура М.П. и Со

.pdf
Скачиваний:
44
Добавлен:
24.02.2016
Размер:
2.38 Mб
Скачать

Приложение 6

используется для закрашивания промежутков между штриховыми линиями, если режим фона – TRANSPARENT, то промежутки между штриховыми линиями не зарисовываются.

Можно создавать кисти, основанные на битовых шаблонах, исполь-

зуя функцию CreatePatternBrush:

hBrush = CreatePatternBrush (hBitmap);

Функция, включающая три рассмотренные ранее функции, строящие кисти:

hBrush = CreateBrushIndirect (&logbrush);

переменная logbrush – структура типа LOGBRUSH («логическая кисть» – logical brush), содержащая поля:

UINT lbStyle – стиль кисти: BS_SOLID – сплошная; BS_HOLLOW,

BS_NULL – «пустая» (невидимая); BS_HATCHED – штрихованная;

BS_PATTERN, BS_PATTERN8X8 – задаются битовой картой; BS_DIBPATTERN, BS_DIBPATTERN8X8, BS_DIBPATTERNPT – задаются битовой картой DIB Windows 95 размер шаблона ограничен 8 8 точек);

COLORREF lbColor – цвет кисти, для пустой или «шаблонной» кисти игнорируется, для кистей с DIB-шаблоном младшее слово определяет, следует ли интерпретировать его цвета как заданные цветовыми компонентами

(DIB_RGB_COLORS) или как палитровые (DIB_PAL_COLORS).

Значение поля lbStyle определяет, как интерпретируются другие поля:

lbStyle

lbColor

lbHatch

BS_SOLID

Цвет кисти

Игнорируется

BS_HOLLOW

Игнорируется

Игнорируется

BS_HATCHED

Цвет штриховых линий

Стиль штриховки

BS_PATTERN

Игнорируется

Описатель битового шаблона

Получить описатель логической кисти: SelectObject (hdc, hBrush); Удалить созданную кисть: DeleteObject (hBrush);

Получить информацию о кисти:

GetObject (hBrush, sizeof (LOGBRUSH), &logbrush);

Инструмент Font

Более сложным инструментом является шрифт. Все символы в оконном интерфейсе формируются в соответствии с одним из зарегистрированных в системе шрифтов.

Физический шрифт – файл (образ в памяти) с описанием начертаний всех известных в данном шрифте символов. Логический шрифт – объект GDI, характеризуемый как физическим шрифтом, так и его конкретными характеристиками. Он же является и инструментом, отвечающим за формирование символов.

Для создания логического шрифта используется функция

221

Приложение 6

HFONT CreateFont (int nHeight, int nWidth, int nEscapement,

int nOrientation, int fnWeight, DWORD fdwItalic, DWORD fdwUnderline, DWORD fdwStrikeOut, DWORD fdwCharSet,

DWORD fdwOutputPrecision, DWORD fdwClipPrecision, DWORD fdwQuality, DWORD fdwPitchAndFamily, LPCTSTR lpszFace);

возвращающая описатель созданного инструмента (NULL – ошибка), параметры:

nHeight – основной размер (высота) шрифта в логических единицах: положительное значение определяет высоту знакоместа, отрицательное – высоту шрифта (после смены знака), нулевое – размер по умолчанию; при неточном соответствии требуемого размера выбирается наибольший, не превышающий требуемый;

nWidth – «приблизительная» ширина шрифта, если 0 – стандартная для выбранного основного размера;

nEscapement – направление вывода строки символов (угол между базовой линией и горизонтальной осью по часовой стрелке в десятых долях градуса);

nOrientation – ориентация отдельного символа (исчисление аналогично предыдущему параметру, в Windows 9x ориентация символов и направление вывода должны совпадать);

fnWeight – толщина символов в условных единицах от 0 до 1000, например: 0 (FW_DONTCARE) – стандартный (по умолчанию), 400 (FW_NORMAL, FW_REGULAR) – стандартная толщина, обычный шрифт, 700 (FW_BOLD) – жирный, выделенный, и т.д.;

fdwItalic, fdwUnderline, fdwStrikeOut – флаги, указывающие, является ли шрифт наклонным, подчеркнутым или перечеркнутым;

fdwCharSet – тип символьного набора: DEFAULT_CHARSET,

ANSI_CHARSET, OEM_CHARSET и т.д. (национальные наборы символов); fdwOutputPrecision – «точность вывода» символов, фактически пред-

почтение типа шрифта при наличии альтернативного выбора:

OUT_DEFAULT_PRECIS, OUT_DEVICE_PRECIS и т.д.; fdwClipPrecision – точность отсечения; fdwQuality – качество вывода;

fdwPitchAndFamily – комбинация по «ИЛИ» двух групп параметров, действующих при неопределенном имени шрифта:

питч (шаг символов) – 2 младших бита: DEFAULT_PITCH,

FIXED_PITCH, VARIABLE_PITCH;

«семейство» шрифта – 4 старших бита: FF_DONTCARE – по умолчанию, FF_MODERN – моноширинные шрифты, FF_ROMAN – «книжные» с засечками (переменный шаг), FF_SWISS – без засечек (переменный шаг), FF_SCRIPT – «рукописные» и курсивные;

222

Приложение 6

lpszFace – имя шрифта, обычно совпадает с именем его дискового файла; если NULL – система подбирает шрифт, наиболее отвечающий заданным требованиям, иначе явно указанный шрифт перекрывает их.

Функция CreateFontIndirect (const LOGFONT* lplgFont); использует в качестве аргумента структуру с полями аналогичного назначения.

Параметры шрифта не включают цвет отображающего инструмента. Управление цветом выводимого текста осуществляется функциями

COLORREF SetTextColor (hdc, crColor); COLORREF GetTextColor (hdc);

Базовой функцией вывода символа является

BOOL TextOut (hdc, nXStart, nYStart, lpString, cbString);

Позицией символа считается верхний левый угол его знакоместа.

6.7. Закрашивание пустот

Если выбранные перо или кисть не сплошные, то они не воздействуют на фоновые промежутки, например, между штрихами, однако эти промежутки заполняются фоновым цветом, для работы с которым служат функции

COLORREF SetBkColor(hdc, crColor); COLORREF GetBkColor(hdc);

первая из которых устанавливает новый, а вторая – получает текущий фоновые цвета; признак ошибки – значение CLR_INVALID. Функция SetBkColor возвращает значение предыдущего цвета.

Функции

int SetBkMode (hdc, iBkMode); int GetBkMode (hdc);

соответственно устанавливают новый или определяют текущий режим фона, 0 – признак ошибки; параметр int iBkMode – режим фона, по умолчанию белый (OPAQUE) – сначала рисуется фон, затем передний план; режим TRANSPARENT – отменяет заполнение пустот, в этом случае цвет фона игнорируется и пустоты заполняться не будут.

6.8. Рисование линий и кривых

Теоретически все, что необходимо драйверу устройства для рисования,

это функции SetPixel и GetPixel.

Значительно более эффективным является использование стандартных функций рисования отрезков и других сложных графических операций.

На представление линий, созданных с использованием функций, влияют атрибуты контекста устройства: текущая позиция, перо, режим фона (для несплошных перьев), цвет фона (для режима фона OPAQUE) и режим рисования.

223

Приложение 6

Функция

LineTo (hdc, xEnd, yEnd);

рисует отрезок прямой из текущего положения пера, определенного в контексте устройства, до точки (xEnd, yEnd), которая не включается в отрезок. В контексте текущее положение пера по умолчанию устанавливается в точку (0,0) и функция LineTo без предварительной установки текущей позиции нарисует отрезок, начинающийся в левом верхнем углу рабочей области окна.

Для рисования отрезка из точки (xStart, yStart) в точку (xEnd, yEnd) необходимо сначала для установки (изменения) текущего положения пера использовать функцию

MoveToEx (hdc, xStart, yStart, &pt);

pt – структура типа POINT, определяющая предыдущую позицию. После чего, используя LineTo (hdc, xEnd, yEnd); будет нарисован отрезок до точки (xEnd, yEnd), не включая ее в отрезок, и текущее положение пера установится в точку (xEnd, yEnd).

Узнать текущее положение пера можно с помощью функции

GetCurrentPositionEx (hdc, &pt);

Следующий фрагмент программы отображает в рабочей области окна сетку с интервалом в 100 пикселей, начиная от левого верхнего угла:

GetClientRect (hwnd, &rect); (см. Пример 1, Сообщение WM_PAINT); for (x = 0; x < rect.right; x += 100) {

MoveToEx (hdc, x, 0, NULL); LineTo (hdc, x, rect.bottom);

}

for (y = 0; y < rect.bottom; y += 100) { MoveToEx (hdc, 0, y, NULL); LineTo (hdc, rect.right, y);

}

Когда необходимо соединить отрезками массив точек pt размером cPoint, можно использовать функцию

Polyline (hdc, pt, cPoint);

Например, определим массив из 5 точек (10 значений), описывающих контур прямоугольника:

POINT pt [5] = { 100, 100, 200, 100, 200, 200, 100, 200, 100, 100 };

используем функцию Polyline (hdc, pt, 5). Следует обратить внимание, что первая и последняя точки совпадают.

Функция Polyline не учитывает и не изменяет текущее положение пера. Функция PolylineTo использует текущее положение для начальной точки и устанавливает текущее положение в конец последнего нарисованного отрезка. Предыдущий пример будет выглядеть

MoveToEx (hdc, pt[0].x, pt[0].y, NULL); PolylineTo (hdc, pt + 1, 4);

224

Приложение 6

Для рисования дуги эллипса (рис. П 6.2) используется функция

Arc (hdc, x1, y1, x2, y2, xStart, yStart, xEnd, yEnd);

в которой значения (x1, y1) задают левый верхний угол, (x2, y2) – правый нижний; (xStart, yStart) – начало дуги; (xEnd, yEnd) – конец дуги.

x S t a r t

x 1

y S t a r t

y 1

x E n d y E n d

y 2 x 2

Рис. П 6.2. Фигура, нарисованная с использованием функции Arc

Чтобы нарисовать одну или более связанных кривых Безье, используются функции

PolyBezier (hdc, pt, iCount); PolyBezierTo (hdc, pt, iCount);

pt – массив структур типа POINT. В функции PolyBezier первые четыре точки идут в таком порядке: начальная точка, первая контрольная точка, вторая контрольная точка, конечная точка кривой Безье. Каждая следующая кривая Безье требует три новых точки, поскольку начальная точка следующей кривой есть конечная точка предыдущей и т.д. Параметр iCount = 1+3*n – равен единице плюс три, умноженное на число отображаемых кривых.

6.9. Пример изображения графика функции sin

Программа содержит массив из 1000 структур POINT. В цикле от 0 до 999 член x структуры растет от 0 до cxClient. В каждом цикле член структуры определяет значение синуса и масштабируется до размеров клиентской области окна. Вся кривая целиком отображается с использованием одного вызова функции Polyline (рис. П 6.3).

Текст программы может быть следующим:

#include <windows.h> #include <math.h> #define NUM 1000

#define TWOPI (2 * 3.14159)

LRESULT CALLBACK WndProc (HWND, UINT, WPARAM, LPARAM) ; int WINAPI WinMain (HINSTANCE hInstance, HINSTANCE hPrevInstance,

PSTR szCmdLine, int iCmdShow)

225

Приложение 6

{

static char szAppName[] = "Sin" ;

HWND

hwnd ;

 

 

MSG

msg ;

 

 

WNDCLASSEX wndclass ;

wndclass.cbSize

= sizeof (wndclass) ;

wndclass.style

= CS_HREDRAW | CS_VREDRAW ;

wndclass.lpfnWndProc

= WndProc ;

wndclass.cbClsExtra

= 0 ;

wndclass.cbWndExtra

= 0 ;

wndclass.hInstance

= hInstance ;

wndclass.hIcon

= LoadIcon (NULL, IDI_APPLICATION) ;

wndclass.hCursor

= LoadCursor (NULL, IDC_ARROW) ;

wndclass.hbrBackground=(HBRUSH) GetStockObject(WHITE_BRUSH); wndclass.lpszMenuName = NULL ;

wndclass.lpszClassName = szAppName ;

wndclass.hIconSm = LoadIcon (NULL, IDI_APPLICATION) ; RegisterClassEx (&wndclass) ;

hwnd = CreateWindow (szAppName, "Second Example", WS_OVERLAPPEDWINDOW, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, NULL, NULL, hInstance, NULL) ;

ShowWindow (hwnd, iCmdShow) ; UpdateWindow (hwnd) ;

while (GetMessage (&msg, NULL, 0, 0)) { TranslateMessage (&msg) ; DispatchMessage (&msg) ;

}

return msg.wParam ;

}

LRESULT CALLBACK WndProc (HWND hwnd, UINT iMsg, WPARAM wParam, LPARAM lParam)

{

static int cxClient, cyClient ;

HDC

hdc ;

int

i ;

PAINTSTRUCT ps ;

POINT

pt [NUM] ;

switch (iMsg) { case WM_SIZE:

cxClient = LOWORD (lParam) ; cyClient = HIWORD (lParam) ;

226

Приложение 6

return 0 ;

case WM_PAINT:

hdc = BeginPaint (hwnd, &ps) ;

MoveToEx (hdc, 0, cyClient / 2, NULL) ; LineTo (hdc, cxClient, cyClient / 2) ;

for (i = 0 ; i < NUM ; i++) { pt[i].x = i * cxClient / NUM ;

pt[i].y = (int) (cyClient / 2 * (1 - sin (TWOPI * i / NUM))) ;

}

Polyline (hdc, pt, NUM) ; return 0 ;

case WM_DESTROY: PostQuitMessage (0) ; return 0 ;

}

return DefWindowProc (hwnd, iMsg, wParam, lParam) ;

}

Результат работы программы:

Рис. П 6.3

6.10. Рисование замкнутых фигур

Рассмотрим функции для рисования замкнутых фигур:

Rectangle – прямоугольник; Ellipse – эллипс; RoundRect – прямоугольник со скругленными углами; Chord – дуга кривой эллипса, концы которой соединены хордой; Pie – кусок, вырезанный из эллипса; Polygon – многоугольник; PolyPolygon – множество многоугольников.

Контур фигуры рисуется текущим пером, а фигура закрашивается текущей кистью. По умолчанию это стандартная кисть WHITE_BRUSH.

Простейшей является функция рисования прямоугольника:

Rectangle (hdc, x1, y1, x2, y2);

(x1, y1) – координаты левого верхнего угла, (x2, y2) – правого нижнего угла.

227

Приложение 6

Для рисования эллипса используется функ-

y 1

 

 

 

 

x 1

 

 

 

 

ция, имеющая те же параметры:

 

 

 

 

 

 

 

 

 

 

Ellipse (hdc, x1, y1, x2, y2);

Фигура, отображаемая функцией Ellipse (вместе с ограничивающим прямоугольником).

Функция для рисования прямоугольника со скругленными углами:

RoundRect (hdc, x1, y1, x2, y2, xEllipse, yEllipse);

y 2

x 2

имеет два дополнительных параметра: для рисования скругленных углов ис-

пользуется маленький эллипс, шириной

x 1

 

 

 

 

 

 

 

x 2

xEllipse, высотой yEllipse. Фигура, ото-

y 1

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

бражаемая этой функцией, приведена на

 

 

 

 

 

 

 

 

 

рисунке. Скругленные углы были нари-

 

 

 

 

 

 

 

 

 

сованы с использованием размеров эл-

 

 

 

 

 

 

 

 

 

липса, вычисленных по формулам

 

 

 

 

 

 

 

 

 

 

y E l l i p s e

 

 

 

 

 

 

 

 

 

xEllipse = (x2–x1)/4; yEllipse = (y2–y1)/4;

 

 

 

 

y 2

 

 

 

 

 

 

 

 

Это простое приближение, но результаты

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

x E l l i p s e

 

 

 

 

 

 

скорее всего будут выглядеть не совсем

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

правильно, потому что округлость углов более заметна при больших размерах прямоугольника.

Функции Chord (сегмент эллипса) и Pie (сектор эллипса) имеют одинаковые параметры:

Chord (hdc, x1, y1, x2, y2, xStart, yStart, xEnd, yEnd); Pie (hdc, x1, y1, x2, y2, xStart, yStart, xEnd, yEnd);

При рисовании используется воображаемая линия для соединения точки (xStart, yStart – начало дуги) с центром эллипса. В точке, где эта линия пересекается с ограничивающим прямоугольником, начинается рисование дуги эллипса в направлении против часовой стрелки; аналогично используется воображаемая линия для соединения точки (xEnd, yEnd – конец дуги) с центром эллипса. В точке, где эта линия пересекается с ограничивающим прямоугольником, завершается рисование дуги.

В функции Chord соединяются конечные точки дуги, а в функции Pie соединяются начальная и конечная точки дуги с центром эллипса.

Фигуры, отображаемые функциями Chord и Pie, приведены на рис. П 6.3.

228

Приложение 6

а

xStart, yStart

б

xStart, yStart

 

 

xEnd, yEnd

xEnd, yEnd

Рис. П 6.3. Фигуры, нарисованные с использованием:

а– функции Chord; б – функции Pie

6.11.Функция Polygon и режим закрашивания многоугольника

Функция рисования многоугольника:

Polygon (hdc, pt, iCount);

pt – это массив структур типа POINT, iCount – число точек; если последняя точка в массиве не совпадает с первой, то добавляется линия, их соединяющая.

Внутренняя область фигуры закрашивается текущей кистью. По умолчанию режим закрашивания равен ALTERNATE (попеременный), т.е. закрашиваются только те фрагменты внутренней области многоугольника, которые получаются путем соединения линий с нечетными номерами (1, 3, 5...), другие фрагменты внутренней области не закрашиваются.

Режим закрашивания устанавливается функцией:

SetPolyFillMode (hdc, iMode);

iMode – режим закрашивания, WINDING (сквозной) – закрашиваются все внутренние области. Для иллюстрации приведем пример:

звезда, находящаяся слева, нарисована в режиме ALTERNATE, а звезда, находящаяся справа – в режиме WINDING.

6.12. Пример отображения линий

Если в предыдущей программе (Second Example) заменить case WM_PAINT... и убрать лишние переменные, получим программу (Third Example), в которой рисуются прямоугольник, эллипс, прямоугольник со скругленными углами и два отрезка. Программа показывает, что функции, определяющие области, закрашивают их, поэтому отрезки не видны там, где нарисован эллипс. Результат работы программы приведен на рис. П 6.4.

229

Приложение 6

. . .

case WM_PAINT:

hdc = BeginPaint (hwnd, &ps) ;

Rectangle (hdc, cxClient /8, cyClient /8, 7*cxClient /8, 7*cyClient /8) ; MoveToEx (hdc, 0, 0, NULL) ;

LineTo (hdc, cxClient, cyClient) ; MoveToEx (hdc, 0, cyClient, NULL) ; LineTo (hdc, cxClient, 0) ;

Ellipse (hdc, cxClient /8, cyClient /8, 7*cxClient /8, 7*cyClient /8) ; RoundRect (hdc, cxClient /4, cyClient /4, 3*cxClient /4, 3*cyClient /4,

 

cxClient /4, cyClient /4) ;

EndPaint (hwnd, &ps) ;

return 0 ;

. . .

Рис. П 6.4. Результат программы Third Example

6.13. Управление областями вывода и отсечением

Стандартно графический вывод отсекается по границам окна, с которым связан контекст, кроме того, из области вывода удаляются части, перекрытые другими окнами. Таким образом, границы области вывода могут иметь достаточно сложную форму.

В среде Windows используются функции, работающие с прямоугольными областями, использующими структуры типа RECT (прямоугольник) и произвольными областями – регионами (regions).

Работа с прямоугольниками

Простейшим средством, задающим границу области вывода, является прямоугольник. Функции отображения прямоугольных областей используют указатель на структуру rect типа RECT (прямоугольник), имеющую поля: left, top, right, bottom, заданные в логических единицах.

Функция FillRect (hdc, &rect, hBrush); закрашивает прямоугольник (не включая правую и нижнюю координаты) заданной кистью.

230