Шрифт:
Листинг 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.15).
Как же достигнут подобный эффект? Очень даже просто. Ведь вы уже знаете, что элементы управления рисуются внутри своих собственных окон (дочерних по отношению к окну формы). Окна элементов отличает отсутствие в их стиле флагов (по – дробнее в гл. 2), позволяющих отображать рамку, изменять размер окна элемента управления. Это легко исправить, самостоятельно задав нужные флаги в стиле окна при помощи API-функции SetWindowLong. Для удобства можно написать отдельную процедуру, которая будет дополнять стиль окна флагами, необходимыми для перемещения и изменения размера (как, собственно, и сделано в примере) (лис – тинг 1.22).
Листинг 1.22.
Разрешение перемещения и изменения размера
procedure MakeMovable(Handle: HWND);
var
style: LongInt;
flags: UINT;
begin
//Разрешаем перемещение элемента управления
style := GetWindowLong(Handle, GWL_STYLE);
style := style or WS_OVERLAPPED or WS_THICKFRAME or WS_CAPTION;
SetWindowLong(Handle, GWL_STYLE, style);
style := GetWindowLong(Handle, GWL_EXSTYLE);
style := style or WS_EX_TOOLWINDOW;
SetWindowLong(Handle, GWL_EXSTYLE, style);
//Перерисуем в новом состоянии
flags := SWP_NOMOVE or SWP_NOSIZE or SWP_DRAWFRAME or
SWP_NOZORDER;
SetWindowPos(Handle, 0, 0, 0, 0, 0, flags);
end;