Регионы — это особые графические объекты, представляющие собой области произвольной формы. Ограничений на форму региона нет, они даже не обязаны быть связными. Существует ряд функций для создания регионов простых форм ( CreateRectRgn
, CreateEllipticRgn
, CreatePolygonRgn
и т.п.), а также функция СombineRgn
для объединения регионов различными способами. Все это вместе позволяет получать регионы любых форм. Область применения регионов достаточно широка. Ранее мы уже видели, как с помощью регионов можно ограничить область вывода графики. Здесь же мы будем с помощью функции SetWindowRgn
изменять форму окна, придавая ему форму заданного региона.
1.3.3.3. Сообщения WM_SIZE и WM_SIZING
События WM_SIZE
и WM_SIZING
позволяют окну реагировать на перемещение его пользователем. В "классическом" варианте, когда пользователь начинает тянуть рамку окна, на экране рисуется "резиновый" прямоугольник, соответствующая сторона или угол которого движется за курсором мыши. Окно получает сообщение WM_SIZING
при каждом изменении размера этого прямоугольника. Параметр lParam
при этом содержит указатель на структуру TRect
с новыми координатами прямоугольника. Окно может не только прочитать эти координаты, но и изменить их, блокировав тем самым нежелательные изменения размера. На этом, в частности, основано использование свойства Constraints
: если размер окна при перемещении становится меньше или больше заданного, при обработке сообщения WM_SIZING
размер увеличивается или уменьшается до необходимого. Параметр wParam
содержит информацию о том, за какую сторону или угол тянет пользователь, чтобы программа знала, координаты какого из углов прямоугольника нужно смещать, если возникнет такая необходимость.
После того как пользователь закончит изменять размеры окна и отпустит кнопку мыши, окно получает сообщение WM_SIZE
. При получении этого сообщения окно должно перерисовать себя с учетом новых размеров. (Окно получает сообщение WM_SIZE
после изменения его размеров по любой причине, а не только из-за действий пользователя.)
Описанный "классический" вариант в чистом виде существует только в Windows 95. Во всех более поздних версиях по умолчанию включена опция отображения содержимого окна при перетаскивании и изменении размеров (начиная с Windows ХР эта опция не только включается по умолчанию, но и не отключается средствами пользовательского интерфейса). В таком режиме при изменении размеров окна вместо прямоугольника "резиновым" становится само окно, и любое перемещение мыши при изменении размеров приводит к перерисовке окна. В этом режиме окно получает сообщение WM_SIZE
каждый раз после сообщения WM_SIZING
, а не только при завершении изменения размеров. Но в целом логика этих сообщений остается прежней, просто с точки зрения программы это выглядит так, как будто пользователь изменяет размеры окна "по чуть-чуть".
1.3.3.4. А теперь — все вместе
Комбинация описанных достаточно простых вещей позволяет построить окно с дыркой, имеющей изменяемые размеры.
Для начала объявим несколько констант, которые нам потребуются при вычислении размеров дырки и т.п. (листинг 1.51).
Листинг 1.51. Константы примера WndHole
const
// минимальное расстояние от дырки до края окна
HoleDistance = 40;
// Зона чувствительности рамки панели - на сколько пикселов
// может отстоять курсор вглубь от края панели, чтобы его
// положение расценивалось как попадание в рамку.
BorderMouseSensivity = 3;
// Зона чувствительности угла рамки панели - на сколько пикселов
// может отстоять курсор от угла панели, чтобы его
// положение расценивалось как попадание в угол рамки.
CornerMouseSensivity = 15;
// Толщина рамки дырки, использующаяся при вычислении региона
HoleBorder = 3;
// Минимальная ширина и высота дырки
MinHoleSize = 10;
// Смещение стрелки относительно соответствующего угла
ArrowOffset = 8;
Теперь приступаем к созданию программы. На форму "кладем" панель. С помощью функции SetWindowRgn
устанавливаем такую форму окна, чтобы от панели была видна только рамка, а на всю внутреннюю часть панели пришлась дырка. Рамку выбираем такую, чтобы панель выглядела утопленной, так края дырки будут выглядеть естественней. Для расчета региона используется метод SetRegion
(листинг 1.52), он вызывается всегда, когда нужно изменить регион окна.
Читать дальше
Конец ознакомительного отрывка
Купить книгу