Соответственно, чтобы сделать такую надпись, нужно создать регион, совпадающий по форме с этой надписью. В GDI есть целый ряд функций для создания регионов различной формы, но вот для создания региона в форме букв функции нет. Зато GDI поддерживает другие объекты — траектории. Строго говоря, это не совсем объекты, траектория не имеет дескриптора (по крайней мере, API не предоставляет этот дескриптор программам), и в каждом контексте устройства может быть только одна траектория. Создание траектории начинается с вызова функции BeginPath
, заканчивается вызовом функции EndPath
. Графические функции, вызванные между BeginPath
и EndPath
, не выводят ничего в контекст устройства, а то, что должно быть выведено, вместо этого запоминается в траектории (которая представляет собой совокупность замкнутых кривых). С траекторией можно выполнить много полезных операций (см., например,BeginPath
и EndPath
мы вызываем DrawText
. формируя таким образом траекторию, состоящую из контуров букв. Затем с помощью функции PathToRegion
мы создаем регион, границы которого совпадают с контурами траектории, т. е., в данном случае, регион, совпадающий по форме с надписью.
На самом деле не все графические функции, вызванные между BeginPath
и EndPath
, добавляют контуры к траектории. Это зависит от версии операционной системы. Подробнее этот вопрос обсуждается в
В ходе работы программы регион не меняется, так что нет нужды создавать его каждый раз при обработке события OnPaint
. Он создается только один раз, и его дескриптор сохраняется в поле FRgn
формы для дальнейшего использования.
Все, что осталось сделать, — это установить регион отсечения с помощью функции SelectClipRgn
, отобразить рисунок и убрать регион отсечения, чтобы не мешал в дальнейшем.
Теперь рассмотрим, как рисуются звезды в правом верхнем углу окна (листинг 1.35).
var
I: Integer;
Star: array[0..4] of TPoint;
…
// Следующая группа команд рисует две звезды справа от
// надписи. Эти звезды демонстрируют использование двух
// режимов заливки: WINDING и ALTERNATE. Для простых
// фигур эти режимы дают одинаковые результаты, разница
// возникает только при закрашивании сложных фигур,
// имеющих самопересечения.
Canvas.Pen.Style:= psSolid;
Canvas.Pen.Width:= 1;
Canvas.Pen.Color:= clRed;
Canvas.Brush.Style:= bsSolid;
Canvas.Brush.Color:= clRed;
// Вычисляем координаты вершин звезды. Они помещаются
// в массив Star в следующем порядке (если первой
// считать верхнюю вершину и нумеровать остальные по
// часовой стрелке от нее): 1-3-5-2-4
for I:= 0 to 4 do
begin
Star[I].X:= Round(380 + 90 * Sin(0.8 * I * Pi));
Star[I].Y:= Round(100 — 90 * Cos(0.8 * I * Pi));
end;
// Устанавливаем режим заливки WINDING. При
// использовании этого режима закрашивается все
// содержимое многоугольника независимо от того,
// как именно он нарисован.
SetPolyFillMode(Canvas.Handle, WINDING);
Canvas.Polygon(Star);
// Сдвигаем координаты звезды, чтобы нарисовать ее
// правее с другим режимом заливки.
for I:= 0 to 4 do Inc(Star([I].X, 200);
// Устанавливаем режим заливки ALTERNATE. При
// использовании этого режима заполняются горизонтальные
// линии, лежащие между нечетной и четной сторонами
// многоугольника. В результате пятиугольник в центре
// звезды оказывается незаполненным.