А. Григорьев - О чём не пишут в книгах по Delphi
- Название:О чём не пишут в книгах по Delphi
- Автор:
- Жанр:
- Издательство:БХВ-Петербург
- Год:2008
- Город:СПб
- ISBN:978-5-9775-019003
- Рейтинг:
- Избранное:Добавить в избранное
-
Отзывы:
-
Ваша оценка:
А. Григорьев - О чём не пишут в книгах по Delphi краткое содержание
Рассмотрены малоосвещённые вопросы программирования в Delphi. Описаны методы интеграции VCL и API. Показаны внутренние механизмы VCL и приведены примеры вмешательства в эти механизмы. Рассмотрено использование сокетов в Delphi: различные механизмы их работы, особенности для протоколов TCP и UDP и др. Большое внимание уделено разбору ситуаций возникновения ошибок и получения неверных результатов в "простом и правильном" коде. Отдельно рассмотрены особенности работы с целыми, вещественными и строковыми типами данных, а также приведены примеры неверных результатов, связанных с ошибками компилятора, VCL и др. Для каждой из таких ситуаций предложены методы решения проблемы. Подробно рассмотрен синтаксический анализ в Delphi на примере арифметических выражений. Многочисленные примеры составлены с учётом различных версий: от Delphi 3 до Delphi 2007. Прилагаемый компакт-диск содержит примеры из книги.
Для программистов
О чём не пишут в книгах по Delphi - читать онлайн бесплатно ознакомительный отрывок
Интервал:
Закладка:
Соответственно, чтобы сделать такую надпись, нужно создать регион, совпадающий по форме с этой надписью. В GDI есть целый ряд функций для создания регионов различной формы, но вот для создания региона в форме букв функции нет. Зато GDI поддерживает другие объекты — траектории. Строго говоря, это не совсем объекты, траектория не имеет дескриптора (по крайней мере, API не предоставляет этот дескриптор программам), и в каждом контексте устройства может быть только одна траектория. Создание траектории начинается с вызова функции BeginPath
, заканчивается вызовом функции EndPath
. Графические функции, вызванные между BeginPath
и EndPath
, не выводят ничего в контекст устройства, а то, что должно быть выведено, вместо этого запоминается в траектории (которая представляет собой совокупность замкнутых кривых). С траекторией можно выполнить много полезных операций (см., например, разд. 1.3.4 ). В нашем случае между вызовами BeginPath
и EndPath
мы вызываем DrawText
. формируя таким образом траекторию, состоящую из контуров букв. Затем с помощью функции PathToRegion
мы создаем регион, границы которого совпадают с контурами траектории, т.е., в данном случае, регион, совпадающий по форме с надписью.
На самом деле не все графические функции, вызванные между BeginPath
и EndPath
, добавляют контуры к траектории. Это зависит от версии операционной системы. Подробнее этот вопрос обсуждается в разд. 1.3.4 .
В ходе работы программы регион не меняется, так что нет нужды создавать его каждый раз при обработке события 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. При
// использовании этого режима заполняются горизонтальные
// линии, лежащие между нечетной и четной сторонами
// многоугольника. В результате пятиугольник в центре
// звезды оказывается незаполненным.
SetPolyFillMode(Canvas.Handle, ALTERNATE);
Canvas.Polygon(Star);
Самое интересное здесь то, что обе звезды рисуются практически одинаково, меняется только режим заливки. Сначала с помощью простейшей тригонометрии вычисляются координаты вершин звезды, помещаются в массив Star
и эта звезда рисуется с режимом заливки WINDING
. При этом закрашиваются все точки, для которых выполняется условие, что луч, выпущенный из этой точки, пересекает контур многоугольника нечетное число раз, т.е. всю внутренность контура. Затем координаты вершин звезды смещаются вправо, и такая же звезда рисуется точно так же, но уже с режимом заливки ALTERNATE
. В этом режиме закрашиваются только те точки, которые оказались между четной и нечетной сторонами многоугольника, и пятиугольник внутри звезды остается незакрашенным. Обратите внимание, что звезду мы здесь рисуем с помощью класса TCanvas
, и только режимы заливки переключаем API-функциями.
Следующий шаг — это рисование черной прямоугольной рамки на фоне пересекающихся зеленых линий. Линии рисуются до рамки для того, чтобы показать, что центр рамки действительно остается прозрачным, а не заливается цветом фона. Сама рамка рисуется вызовом одной функции PolyPolygon
, позволяющей за один раз нарисовать фигуру, ограниченную несколькими замкнутыми многоугольными контурами (листинг 1.36).
PolyPolygon
const
Pts: array[0..7] of TPoint = (
(X: 40; Y: 230), (X: 130; Y: 230),
(X: 130; Y: 320), (X: 40; Y: 320),
(X: 60; Y: 250), (X: 60; Y: 300),
(X: 110; Y: 300), (X: 110; Y: 250));
Cnt: array[0..1] of Integer = (4, 4);
...
// Следующая группа команд рисует прямоугольную рамку
Canvas.Pen.Color := clLime;
Canvas.Pen.Width := 3;
// Эти линии рисуются для того, чтобы показать, что
// центр рамки остается прозрачным.
Canvas.MoveTo(30, 220);
Canvas.LineTo(140, 330);
Canvas.MoveTo(140, 220);
Canvas.LineTo(30, 330);
Canvas.Pen.Color := clBlack;
Canvas.Brush.Color := clBlack;
// Функция PolyPolygon позволяет нарисовать несколько
// многоугольников одной командой. Второй параметр
// задает координат всех многоугольников, третий
// параметр задает массив, содержащий число вершин
// каждого из многоугольников. В нашем случае массив
// Cnt имеет значение (4, 4). Это значит, что первые
// четыре элемента массива PCs задают координаты первого
// многоугольника, следующие четыре - второго. Отметим,
// что указатели на массивы приходится передавать не
// очень простым способом: сначала нужно получить
// указатель на массив с помощью оператора @, а потом
// этот указатель разыменовать. Формальные параметры,
// определяющие указатели на массив, при импорте функции
// PolyPolygon в модуле Windows.dcu объявлены как
// нетипизированные параметры-переменные, поэтому
// компилятор не разрешает просто передать Pts и Cnt в
// качестве фактических параметров - он запрещает
Интервал:
Закладка: