Чтение онлайн

на главную - закладки

Жанры

О чём не пишут в книгах по Delphi

Григорьев Антон Борисович

Шрифт:

 Pt := ScreenToClient(Point(Msg.XPos, Msg.YPos));

 // Проверяем координаты на попадание в регионы стрелок

 if PtInRegion(ArrowTopLeft, Pt.X, Pt.Y) then

Msg.Result := HTTOPLEFT

 else if PtInRegion(ArrowTopRight, Pt.X, Pt.Y) then

Msg.Result := HTTOPRIGHT

 else

if PtInRegion(ArrowBottomLeft, Pt.X, Pt.Y) then

Msg.Result := HTBOTTOMLEFT

else

if PtInRegion(ArrowBottomRight, Pt.X, Pt.Y) then

Msg.Result := HTBOTTOMRIGHT;

end;

Вот

и все. С помощью нескольких нехитрых приемов мы получили окно, которое имеет такой необычный вид (см. рис. 1.14).

1.3.4. Обобщающий пример 4 — Линии нестандартного стиля

GDI позволяет рисовать линии разных стилей, но бывают ситуации, когда стандартных возможностей по изменению стиля линий не хватает. В этом разделе мы покажем, как рисовать линии произвольного стиля (начнем с прямых, потом перейдем к кривым Безье), а также сделаем "резиновую" линию, которую пользователь может тянуть мышью.

1.3.4.1. Получение координат точек прямой

Рисование нестандартных линий выполняется следующим образом: вычисляются координаты всех пикселов, составляющих данную прямую, а потом каждый из них (а при необходимости — и какая-либо его окрестность) раскрашиваются нужным цветом. Следовательно, возникает вопрос об определении координат пикселов.

Существует ряд алгоритмов вычисления этих координат. Наиболее известный из них — алгоритм Брезенхэма (Bresengham), который заключается в равномерном разбрасывании "ступенек" разной длины вдоль линии. В Windows используется алгоритм GIQ (Grid Intersection Quantization). Каждый пиксел окружается воображаемым ромбом из четырех пикселов. Если прямая имеет общие точки с этим ромбом, то пиксел рисуется.

Самостоятельно реализовывать один из таких алгоритмов нет необходимости — в Windows существует функция

LineDDA
, которая возвращает вызвавшей ее программе координаты линии. Эта функция в качестве параметра принимает координаты начала и конца линии, а также указатель на функцию, которой будут передаваться координаты пикселов. Данная функция должна быть реализована в программе. За время выполнения
LineDDA
эта функция будет вызвана столько раз, сколько пикселов содержит линия (как обычно в Windows, последний пиксел не считается принадлежащим прямой). Каждый раз при вызове ей будут передаваться координаты очередного пиксела, причем пикселы будут упорядочены от начала к концу прямой.

В примере Lines (рис. 1.15) с помощью

LineDDA
рисуется пять различных типов линий. Рассмотрим на примере самого сложного из реализуемых программой типов линии ("Зеленая елочка"), как это делается (листинг 1.58).

Рис. 1.15. Окно программы Lines

Листинг 1.58. Рисование линии сложного стиля

// константы для типа "Зеленая елочка"

const

 // Угол отклонения "иголки" от направления линии

 FirNeedleAngle = 30;

 //Длина иголки

 FirNeedleLength = 8;

var

 Counter: Integer; // Счетчик точек линии

 // Вспомогательные переменные для построения "елочки"

 DX1, DY1, DX2, DY2: Integer;

// Линия в виде "елочки"

procedure LineDrawFir(X, Y: Integer; Canvas: TCanvas); stdcall;

begin

 with Canvas do case Counter mod 10 of

0: begin

MoveTo(X, Y);

LineTo(X + DX1, Y + DY1);

end;

5:

begin

MoveTo(X, Y);

LineTo(X + DX2, Y + DY2);

end;

 end;

 Inc(Counter);

end;

procedure TLinesForm.Line(X1, Y1, X2, Y2: Integer);

var

 Angle: Extended;

begin

 case RGroupLine.ItemIndex of

...

4:

 begin

Counter := 0;

Angle := ArcTan2(Y2 - Y1, X2 - X1);

DX1 := Round(FirNeedleLength *

Cos(Angle + Pi / 180 * FirNeedleAngle));

DY1 := Round(FirNeedleLength *

Sin(Angle + Pi / 180 * FirNeedleAngle));

DX2 := Round(FirNeedleLength *

Cos(Angle - Pi / 180 * FirNeedleAngle));

DY2 := Round(FirNeedleLength *

Sin(Angle - Pi / 180 * FirNeedleAngle));

LineDDA(X1, Y1, X2, Y2, @LineDrawFir, Integer(Canvas));

end;

 end;

end;

Каждая "иголка" —

это линия длиной
FirNeedleLength
пикселов, отклоняющаяся от направления прямой на угол
FirNeedleAngle
градусов. "Иголки" отклоняются попеременно то в одну, то в другую сторону от прямой. В процедуре
Line
сначала рассчитываются смещения координат конца "иголки" относительно начала и результаты помещаются в глобальные переменные
DX1
,
DY1
,
DX2
,
DY2
. Переменная
Counter
служит для определения номера точки. Перед вызовом
LineDDA
она инициализируется нулем. Затем вызывается функция
LineDDA
, в качестве одного из параметров которой передается указатель на функцию обратного вызова
LineDrawFir
. В результате этого функция
LineDrawFir
будет вызвана последовательно для каждого из пикселов, составляющих линию, начиная с (X1, Y1).
LineDrawFir
ведет подсчет пикселов, каждый раз увеличивая
Counter
на единицу. Если остаток от деления номера точки на 10 равен 0, рисуется "иголка", отклоняющаяся в положительном направлении, если 5 — в отрицательном. В остальных случаях не рисуется ничего. Так получается "елочка".

1.3.4.2. "Резиновая" линия и растровые операции

Теперь нужно дать пользователю возможность рисовать линии. Для этого мы используем стандартную "резиновую" линию: пользователь нажимает левую кнопку мыши и, удерживая ее, передвигает мышь. До тех пор, пока кнопка удерживается, за курсором тянется линия. Как только пользователь отпускает кнопку, линия "впечатывается" в рисунок.

Сама по себе реализация "резиновой" линии очень проста: при наступлении события

OnMouseDown
запоминаются координаты начала линии и взводится флаг, показывающий, что включен режим рисования "резиновой" линии. Также запоминаются координаты конца отрезка, который на данный момент совпадает с началом. В обработчике
OnMouseMove
, если включен режим рисования "резиновой" линии, стирается линия со старыми координатами конца и рисуется с новыми. При наступлении
OnMouseUp
программа выходит из режима рисования "резиновой" линии, рисуя окончательный ее вариант с текущими координатами конца.

Поделиться:
Популярные книги

Черный Маг Императора 6

Герда Александр
6. Черный маг императора
Фантастика:
юмористическое фэнтези
попаданцы
аниме
7.00
рейтинг книги
Черный Маг Императора 6

Оцифрованный. Том 1

Дорничев Дмитрий
1. Линкор Михаил
Фантастика:
боевая фантастика
попаданцы
аниме
5.00
рейтинг книги
Оцифрованный. Том 1

Кодекс Охотника. Книга XIV

Винокуров Юрий
14. Кодекс Охотника
Фантастика:
боевая фантастика
попаданцы
аниме
5.00
рейтинг книги
Кодекс Охотника. Книга XIV

Штуцер и тесак

Дроздов Анатолий Федорович
1. Штуцер и тесак
Фантастика:
боевая фантастика
альтернативная история
8.78
рейтинг книги
Штуцер и тесак

Я снова граф. Книга XI

Дрейк Сириус
11. Дорогой барон!
Фантастика:
боевая фантастика
попаданцы
аниме
5.00
рейтинг книги
Я снова граф. Книга XI

Болотник

Панченко Андрей Алексеевич
1. Болотник
Фантастика:
попаданцы
альтернативная история
6.50
рейтинг книги
Болотник

Кодекс Крови. Книга III

Борзых М.
3. РОС: Кодекс Крови
Фантастика:
фэнтези
попаданцы
аниме
5.00
рейтинг книги
Кодекс Крови. Книга III

Жестокая свадьба

Тоцка Тала
Любовные романы:
современные любовные романы
4.87
рейтинг книги
Жестокая свадьба

Стеллар. Трибут

Прокофьев Роман Юрьевич
2. Стеллар
Фантастика:
боевая фантастика
рпг
8.75
рейтинг книги
Стеллар. Трибут

Голодные игры

Коллинз Сьюзен
1. Голодные игры
Фантастика:
социально-философская фантастика
боевая фантастика
9.48
рейтинг книги
Голодные игры

Последняя Арена 8

Греков Сергей
8. Последняя Арена
Фантастика:
боевая фантастика
рпг
5.00
рейтинг книги
Последняя Арена 8

Черный маг императора 2

Герда Александр
2. Черный маг императора
Фантастика:
юмористическая фантастика
попаданцы
аниме
6.00
рейтинг книги
Черный маг императора 2

Последний Паладин

Саваровский Роман
1. Путь Паладина
Фантастика:
фэнтези
попаданцы
аниме
5.00
рейтинг книги
Последний Паладин

Измена. Свадьба дракона

Белова Екатерина
Любовные романы:
любовно-фантастические романы
эро литература
5.00
рейтинг книги
Измена. Свадьба дракона