KnigaRead.com/
KnigaRead.com » Компьютеры и Интернет » Программы » Валерий Борисок - Delphi. Трюки и эффекты

Валерий Борисок - Delphi. Трюки и эффекты

На нашем сайте KnigaRead.com Вы можете абсолютно бесплатно читать книгу онлайн Валерий Борисок, "Delphi. Трюки и эффекты" бесплатно, без регистрации.
Перейти на страницу:

Рис. 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;

В листинге 1.20 подразумевается использование файла back.bmp, находящегося в той же папке, что и файл приложения. Цвет фона – белый. Таким образом, если шаблон, показанный на рис. 1.11, хранится в файле back. bmp, то получим форму, как на рис. 1.12.

Рис. 1.12. Результат построения региона по шаблону

1.5. Немного о перемещении окон

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

Перемещение за клиентскую область

Здесь на конкретном примере (перемещение формы за любую точку клиентской области) продемонстрировано, как можно самостоятельно определять положение некоторых важных элементов окна. Под элементами окна здесь подразумеваются:

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

• границы окна (при щелчке кнопкой мыши на верхней, нижней, правой и левой границе можно изменять размер окна, если, правда, стиль окна это допускает);

• четыре угла окна (предназначены для изменения размера окна при помощи мыши);

• системные кнопки – закрытия, разворачивания, сворачивания, контекстной справки (обычно расположены в строке заголовка окна);

• полосы прокрутки – горизонтальная и вертикальная;

• системное меню (раскрывается при щелчке кнопкой мыши на значке окна);

• меню – полоса меню, обычно вверху окна;

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

Каждый раз, когда над окном перемещается указатель мыши либо происходит нажатие кнопки мыши, система посылает соответствующему окну сообщение WM_NCHITTEST для определения того, над какой из перечисленных выше областей окна находится указатель. Обработчик этого сообщения, вызываемый по умолчанию, информирует систему о расположении элементов окна в привычных для нас местах: заголовка – сверху, правой границы – справа и т. д.

Как вы, скорее всего, уже догадались, реализовав свой обработчик сообщения WM_NCHITTEST, можно изменить назначение элементов окна. Этот прием как раз и используется в листинге 1.21.

...

Листинг 1.21. Перемещение окна за клиентскую область

procedure TfrmMoveClient.WMNCHitTest(var Message: TWMNCHitTest);

var

rc: TRect;

p: TPoint;

begin

//Если точка приходится на клиентскую область, то заставим

//систему считать эту область частью строки заголовка

rc := GetClientRect();

p.X := Message.XPos;

p.Y := Message.YPos;

p := ScreenToClient(p);

if PtInRect(rc, p) then

Message.Result := HTCAPTION

else

//Обработка по умолчанию

Message.Result := DefWindowProc(Handle, Message.Msg, 0,

65536 * Message.YPos + Message.XPos);

end;

Приведенный в листинге 1.21 обработчик переопределяет положение только строки заголовка, возвращая значение HTCAPTION. Этот обработчик может возвращать следующие значения (целочисленные константы, возвращаемые функцией DefWindowProc):

• HTBORDER – указатель мыши находится над границей окна (размер окна не изменяется);

• НТВОТТОМ, НТТОР, HTLEFT, HTRIGHT – над нижней, верхней, левой или правой границей окна соответственно (размер окна можно изменить, «потянув» за границу);

• HTBOTTOMLEFT, HTBOTTOMRIGHT, HTTOPLEFT, HTTOPRIGHT – В левом нижнем, правом нижнем, левом верхнем или правом верхнем углу окна (размер окна можно изменять по диагонали);

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

• HTCAPTION – над строкой заголовка окна (за это место окно перемещается);

• HTCLIENT – над клиентской областью окна;

• HTCLOSE – над кнопкой закрытия окна;

• HTHELP – над кнопкой вызова контекстной справки;

• HTREDUCE, HTMINBUTTON – над кнопкой минимизации окна;

• HTZOOM, HTMAXBUTTON – над кнопкой максимизации окна;

• HTMENU – над полоской меню окна;

• HTSYSMENU – над значком окна (используется для вызова системного меню);

• HTHSCROLL, HTVSCROLL – указатель находится над вертикальной или горизонтальной полосой прокрутки соответственно;

• HTTRANS PARENT – если возвращается это значение, то сообщение пересылается окну, находящемуся под данным окном (окна должны принадлежать одному потоку);

• HTNOWHERE – указатель не находится над какой-либо из областей окна (например, на границе между окнами);

• HTERROR – то же, что и NTNOWHERE, только при возврате этого значения обработчик по умолчанию (DefWindowProc) воспроизводит системный сигнал, говорящий об ошибке.

Перемещаемые элементы управления

В завершение материала о перемещении окон приведем один совсем несложный, но довольно интересный пример, позволяющий прямо «на лету» модифицировать внешний вид приложения, перемещая и изменяя размер элементов управления так, как будто это обычные перекрывающиеся окна.

Чтобы вас заинтересовать, сразу приведем результат работы примера. Итак, на рис. 1.13 показан внешний вид формы в начале работы примера.

Рис. 1.13. Первоначальный вид формы

Теперь устанавливаем флажок Перемещение элементов управления и получаем результат, показанный на рис. 1.14.

Рис. 1.14. Элементы управления можно перемещать (флажок не учитывается)

Выполняем произвольные перемещения, изменение размера окон, занявших место элементов управления, снимаем флажок и получаем результат – измененный интерфейс формы (рис. 1.15).

Рис. 1.15. Внешний вид формы после перемещения элементов управления

Как же достигнут подобный эффект? Очень даже просто. Ведь вы уже знаете, что элементы управления рисуются внутри своих собственных окон (дочерних по отношению к окну формы). Окна элементов отличает отсутствие в их стиле флагов (по – дробнее в гл. 2), позволяющих отображать рамку, изменять размер окна элемента управления. Это легко исправить, самостоятельно задав нужные флаги в стиле окна при помощи API-функции SetWindowLong. Для удобства можно написать отдельную процедуру, которая будет дополнять стиль окна флагами, необходимыми для перемещения и изменения размера (как, собственно, и сделано в примере) (лис – тинг 1.22).

Перейти на страницу:
Прокомментировать
Подтвердите что вы не робот:*