Перемещение за клиентскую область
Здесь на конкретном примере (перемещение формы за любую точку клиентской области) продемонстрировано, как можно самостоятельно определять положение некоторых важных элементов окна. Под элементами окна здесь подразумеваются:
• строка заголовка (не только предназначена для отображения текста заголовка, но и служит областью захвата при перемещении окна мышью);
• границы окна (при щелчке кнопкой мыши на верхней, нижней, правой и левой границе можно изменять размер окна, если, правда, стиль окна это допускает);
• четыре угла окна (предназначены для изменения размера окна при помощи мыши);
• системные кнопки – закрытия, разворачивания, сворачивания, контекстной справки (обычно расположены в строке заголовка окна);
• полосы прокрутки – горизонтальная и вертикальная;
• системное меню (раскрывается при щелчке кнопкой мыши на значке окна);
• меню – полоса меню, обычно вверху окна;
• клиентская область – по умолчанию все пространство окна, кроме строки заголовка, меню и полос прокрутки.
Каждый раз, когда над окном перемещается указатель мыши либо происходит нажатие кнопки мыши, система посылает соответствующему окну сообщение 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 – над нижней, верхней, левой или правой границей окна соответственно (размер окна можно изменить, «потянув» за границу);