Читаем О чём не пишут в книгах по Delphi полностью

События WM_SIZE и WM_SIZING позволяют окну реагировать на перемещение его пользователем. В "классическом" варианте, когда пользователь начинает тянуть рамку окна, на экране рисуется "резиновый" прямоугольник, соответствующая сторона или угол которого движется за курсором мыши. Окно получает сообщение WM_SIZING при каждом изменении размера этого прямоугольника. Параметр lParam при этом содержит указатель на структуру TRect с новыми координатами прямоугольника. Окно может не только прочитать эти координаты, но и изменить их, блокировав тем самым нежелательные изменения размера. На этом, в частности, основано использование свойства Constraints: если размер окна при перемещении становится меньше или больше заданного, при обработке сообщения WM_SIZING размер увеличивается или уменьшается до необходимого. Параметр wParam содержит информацию о том, за какую сторону или угол тянет пользователь, чтобы программа знала, координаты какого из углов прямоугольника нужно смещать, если возникнет такая необходимость.

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

Описанный "классический" вариант в чистом виде существует только в Windows 95. Во всех более поздних версиях по умолчанию включена опция отображения содержимого окна при перетаскивании и изменении размеров (начиная с Windows ХР эта опция не только включается по умолчанию, но и не отключается средствами пользовательского интерфейса). В таком режиме при изменении размеров окна вместо прямоугольника "резиновым" становится само окно, и любое перемещение мыши при изменении размеров приводит к перерисовке окна. В этом режиме окно получает сообщение WM_SIZE каждый раз после сообщения WM_SIZING, а не только при завершении изменения размеров. Но в целом логика этих сообщений остается прежней, просто с точки зрения программы это выглядит так, как будто пользователь изменяет размеры окна "по чуть-чуть".

<p>1.3.3.4. А теперь — все вместе</p></span><span>

Комбинация описанных достаточно простых вещей позволяет построить окно с дыркой, имеющей изменяемые размеры.

Для начала объявим несколько констант, которые нам потребуются при вычислении размеров дырки и т.п. (листинг 1.51).

Листинг 1.51. Константы примера WndHole

const

 // минимальное расстояние от дырки до края окна

 HoleDistance = 40;

 // Зона чувствительности рамки панели - на сколько пикселов

 // может отстоять курсор вглубь от края панели, чтобы его

 // положение расценивалось как попадание в рамку.

 BorderMouseSensivity = 3;

 // Зона чувствительности угла рамки панели - на сколько пикселов

 // может отстоять курсор от угла панели, чтобы его

 // положение расценивалось как попадание в угол рамки.

 CornerMouseSensivity = 15;

 // Толщина рамки дырки, использующаяся при вычислении региона

 HoleBorder = 3;

 // Минимальная ширина и высота дырки

 MinHoleSize = 10;

 // Смещение стрелки относительно соответствующего угла

 ArrowOffset = 8;

Теперь приступаем к созданию программы. На форму "кладем" панель. С помощью функции SetWindowRgn устанавливаем такую форму окна, чтобы от панели была видна только рамка, а на всю внутреннюю часть панели пришлась дырка. Рамку выбираем такую, чтобы панель выглядела утопленной, так края дырки будут выглядеть естественней. Для расчета региона используется метод SetRegion (листинг 1.52), он вызывается всегда, когда нужно изменить регион окна.

Листинг 1.52. Метод SetRegion, устанавливающий регион окна

procedure TFormHole.SetRegion;

var

 Rgn1, Rgn2: HRGN;

 R, R2: TRect;

begin

 // Создаем регион, соответствующий прямоугольнику окна

 Rgn1 := CreateRectRgn(0, 0, Width, Height);

 // Нам потребуются координаты панели относительно левого

 // верхнего угла окна (а не относительно левого верхнего

Перейти на страницу:
Нет соединения с сервером, попробуйте зайти чуть позже