Excel. Трюки и эффекты
Шрифт:
Пятиугольная звезда, используемая как область отсечения формы, создается при помощи приведенной в листинге 1.15 процедуры Make5Angle. После изменяется порядок следования вершин пятиугольника, чтобы их обход при построении региона выполнялся так, как рисуется звезда карандашом на бумаге (например, 1-3-5-2-4) (листинг 1.16).
Листинг 1.16.
Создание пятиугольной звезды
procedure MakeStar(width, height: Integer; var points: array
of TPoint);
begin
Make5Angle(width, height, points);
//При построении звезды точки пятиугольника обводятся не по
//порядку,а через одну
Swap(points[1], points[2]);
Swap(points[2], points[4]);
Swap(points[3], points[4]);
end;
Процедура MakeStart (листинг 1.16)
Комбинированные регионы
Вы уже научились создавать и использовать простые регионы. Однако многим может показаться недостаточным тех форм окон, которые получаются с использованием лишь одного несложного региона в качестве области отсечения. Пришло время заняться созданием окон более сложной формы, применяя рассмотренные ранее операции над регионами.
«Дырявая» форма
Этот простейший пример сомнительной полезности предназначен для знакомства с операциями над регионами. Здесь применяется только одна из возможных операций – операция XOR для формирования «дырок» в форме (рис. 1.8).
Рис. 1.8. «Дырки» в форме
На рис. 1.8 явно видно, как в «дырках» просвечивается одно из окон среды разработки Delphi. При этом сообщения от мыши, когда указатель находится над «дыркой», получает не наше окно, а те, часть которых видна в «дырке». Программный код, приводящий к созданию формы столь необычного вида, приведен в листинге 1.17.
Листинг 1.17.
Создание «дырок» в форме
procedure TfrmHole.FormCreate(Sender: TObject);
var
rgn1, rgn2: HRGN; //"Регионы-дырки" в форме
formRgn: HRGN;
begin
//Создание региона для формы
formRgn := CreateRectRgn(0, 0, Width – 1, Height – 1);
//Создание регионов для «дырок»
rgn1 := CreateEllipticRgn(10, 10, 100, 50);
rgn2 := CreateRoundRectRgn(10, 60, 200, 90, 10, 10);
//Создание «дырок» в регионе формы
CombineRgn(formRgn, formRgn, rgn1, RGN_XOR);
CombineRgn(formRgn, formRgn, rgn2, RGN_XOR);
SetWindowRgn(Handle, formRgn, True);
//Регионы для «дырок» больше не нужны
DeleteObject(rgn1);
DeleteObject(rgn2);
end;
Сложная комбинация регионов
Теперь пришла очередь более сложного, но и гораздо более интересного примера. Последовательное применение нескольких операций над регионами приводит к созданию формы, показанной на рис. 1.9 (белое пространство – это вырезанные части формы).
Рис. 1.9. Сложная комбинация регионов
Процедура, в которой производятся операции над регионами, приведена в листинге 1.18.
Листинг 1.18.
Сложная комбинация регионов
procedure TfrmManyRgn.FormCreate(Sender: TObject);
var
r1, r2, r3, r4, r5, r6, r7: HRGN;
formRgn: HRGN;
butRgn: HRGN;
begin
//Создание регионов
r1 := CreateRoundRectRgn(100, 0, 700, 400, 40, 40);
r2 := CreateRectRgn(280, 0, 300, 399);
r3 := CreateRectRgn(500, 0, 520, 399);
r4 := CreateEllipticRgn(140, 40, 240, 140);
r5 := CreateEllipticRgn(0, 300, 200, 500);
r6 := CreateEllipticRgn(500, 40, 600, 140);
r7 := CreateEllipticRgn(540, 40, 640, 140);
//Комбинирование
//..разрезы в основном регионе
CombineRgn(r1, r1, r2, RGN_XOR);
CombineRgn(r1, r1, r3, RGN_XOR);
//..круглая «дырка» в правой стороне
CombineRgn(r1, r1, r4, RGN_XOR);
//..присоединение круга в левой нижней части
CombineRgn(r1, r1, r5, RGN_OR);
//..создание «дырки» в форме полумесяца
CombineRgn(r7, r7, r6, RGN_DIFF);
CombineRgn(r1, r1, r7, RGN_XOR);
formRgn := CreateRectRgn(0, 0, 0, 0);
CombineRgn(formRgn, r1, 0, RGN_COPY);
DeleteObject(r1);
DeleteObject(r2);
DeleteObject(r3);
DeleteObject(r4);
DeleteObject(r5);
DeleteObject(r6);
DeleteObject(r7);
//Создание круглой кнопки закрытия
butRgn := CreateEllipticRgn(50, 50, 150, 150);
SetWindowRgn(Button1.Handle, butRgn, False);
SetWindowRgn(Handle, formRgn, True);
end;
В листинге подписано, какие операции для создания каких элементов итогового региона предназначены. В операциях участвуют семь регионов. Расположение используемых в операциях регионов показано на рис. 1.10.
Рис. 1.10. Элементарные регионы, используемые для получения формы на рис. 1.9.
Использование шаблона
Предыдущий пример наглядно демонстрирует мощь функции CombineRgn при построении регионов сложной формы. Однако существует огромное количество предметов, контуры которых крайне сложно повторить, комбинируя простые регионы. Построение многоугольных регионов с большим количеством точек может в этом случае нас выручить, но ведь это крайне нудно и утомительно.
Если есть изображение предмета, контуры которого должны совпадать с контурами региона, то гораздо проще при построении региона обрабатывать само изображение, отбирая все точки, для которых выполняется определенное условие. Изображение и будет тем шаблоном, по которому «вырезается» регион нужной формы.
Рассмотрим простейший пример: есть монохромное изображение, каждая точка которого должна попасть в результирующий регион, если ее цвет не совпадает с заданным цветом фона. При этом изображение анализируется по так называемым «скан-линиям», то есть построчно. Из подряд идущих точек не фонового цвета формируются прямоугольные регионы, которые объединяются с результирующим регионом. Пример возможного шаблона приведен на рис. 1.11.
Рис. 1.11. Пример растрового изображения-шаблона
Функция построения региона указанным способом приведена в листинге 1.19.
Листинг 1.19. Построение региона по шаблону
function RegionFromPicture(pict: TPicture; backcolor: TColor):
HRGN;
var
rgn, resRgn: HRGN;
x, y, xFirst: Integer;
begin
resRgn := CreateRectRgn(0, 0, 0, 0); //Результирующий регион
//Анализируем каждую скан-линию рисунка (по горизонтали)
for y := 0 to pict.Height – 1 do
begin
x := 0;
while x < pict.Width do
begin
if (pict.Bitmap.Canvas.Pixels[x, y] <> backcolor) then
begin
xFirst := x;
Inc(x);
//Определим часть линии, окрашенной не цветом фона
while (x < pict.Width) and
(pict.Bitmap.Canvas.Pixels[x, y] <> backcolor) do Inc(x);
//Создаем регион для части скан-линии и добавляем его
//к результурующему региону
rgn := CreateRectRgn(xFirst, y, x–1, y+1);
CombineRgn(resRgn, resRgn, rgn, RGN_OR);
DeleteObject(rgn);
end;
Inc(x);
end;
end;
RegionFromPicture := resRgn;
end;
Загрузка изображения-шаблона и создание региона может происходить, например, при создании формы следующим образом (листинг 1.20).
Листинг 1.20.
Создание региона для области отсечения формы
procedure TfrmTemplate.FormCreate(Sender: TObject);
var
pict: TPicture;
begin
//Загрузка изображения и создание региона (считаем, что
//цвет фона – белый)
pict := TPicture.Create;
pict.LoadFromFile(\'back.bmp\');
SetWindowRgn(Handle, RegionFromPicture(pict, RGB(255,255,255)),
True);
end;