Мы продолжаем учиться программировать. И снова я покажу, что достаточно сложные на первый взгляд вопросы решаются очень легко. Сегодня ты научишься заставлять окна плавать. Плавать они будут не в бассейне, а по экрану, наше окно можно будет перетащить за любую его часть. А самое главное, мы рассмотрим аж два способа решения этой задачи.
Сначала рассмотрим тот, что попроще. Для этого создайте новый проект. В разделе private новой формы напишите:
Теперь нажми клавиши Ctrl+Alt+C , после этого Delphi создаст пустую процедуру:
procedure TForm1.WMNCHitTest(var M: TWMNCHitTest);
begin
end;
Внутри неё напиши следующее:
inherited;
if M.Result = htClient then
M.Result := htCaption;
Теперь запусти программу и попробуй перетащить окно за форму. Получилось? Это хорошо, теперь рассмотрим, что мы для этого сделали. Самое первое, это мы объявили процедуру - обработчик для события HitTest. Это событие происходит, когда тестируется щёлчок мышки по окну. Это событие мы объявляли не так как предыдущие (через Object Inspector), а вручную как обычную процедуру. О том что это обработчик события говорит надпись в объявлении после точки с запятой: message wm_NCHitTest; .
Внутри обработчика события мы вызываем предка с помощью inherited; , чтобы сначала он обработал это событие. А после этого мы проверяем следующее: если щелчок был по форме, то мы заставляем Microsoft думать, что щелчок был по заголовку окна. Всё очень просто. Взгляни ещё раз на этот код, и ты это поймёшь.
Теперь мы сделаем тоже самое вторым способом. Он немного тяжелее, но зато он позволяет перетаскивать окна за любой компонент. Приготовь новый проект, мы начинаем.
Создай на форме из палитры компонентов TPanel (рис 1.) и создай для неё обработчик события OnMouseDown . В этой процедуре напиши следующее:
procedure TForm1.Panel1MouseDown(Sender: TObject;
Button:TMouseButton;Shift:TShiftState;X,Y:Integer);
Begin
if Button = mbLeft then
begin
ScreenDC := GetDC(0);
OldX := X; // сохраняем Х координату щелчка
OldY := Y; // сохраняем Y координату щелчка
OldLeft := X; // сохраняем Х координату щелчка
OldTop := Y; // сохраняем Y координату щелчка
MoveRect := BoundsRect; // // сохраняем размеры и положение окна
DrawFocusRect(ScreenDC, MoveRect); // Рисуем рамочку окна.
Dragging := True; // Начинаем перемещение.
end;
end;
Процедура нам передаёт параметр Button , в котором хранится значение нажатой кнопки мыши (возможны значения mbLeft, mbRight и mbMiddle). В первой строчке мы проверяем, нажата ли левая кнопка. Если это была левая, то мы начинаем приготовления к перетаскиванию окна. Практически всё ты сможешь понять по комментариям, но некоторые вещи я объясню.
GetDC создаёт контекст устройства к указанному в скобках окну, и записывает это, в объявленную нами переменную ScreenDC. В качестве параметра мы передаём ноль, а не ссылку на окно. В этом случае мы получим контекст рисования на всём экране. Контекст устройства - это нечто похожее на Canvas, только второй имеет больше возможностей и более удобен в работе.
DrawFocusRect эта функция рисует рамочку на контексте, переданном в качестве первого параметра, и размерами, переданными в качестве второго параметра. В качестве размера мы передаём текущее положение экрана.
Теперь нужно создать обработчик события OnMouseMove (когда переместили мышку). Внутри обработчика напиши следующее:
if Dragging then begin //Если происходит перемещение то ….
DrawFocusRect(ScreenDC,MoveRect);
OldX := X; // Сохраняем новое положение экрана
OldY := Y; // Сохраняем новое положение экрана
MoveRect := Rect(Left+OldX-OldLeft,Top+OldY-OldTop,
Left+Width+OldX-OldLeft,Top+Height+OldY-OldTop);
DrawFocusRect(ScreenDC,MoveRect);
end;
Первый вызов процедуры DrawFocusRect рисует рамку поверх предыдущей. Это нужно для того, чтобы стереть её. Если дважды вывести рамку в одном и том же месте, то результат будет нулевым. Затем сохраняются новое положение окна, переданные нам обработчиком. Далее вычисляются новые размеры рамки, и записываются в MoveRect . И снова вызывается DrawFocusRect , которая рисует рамку в новом положении окна.
Теперь создаём обработчик события OnMouseUp (когда отпустили мышку) и записываем следующее:
if Button = mbLeft then begin // Если это была левая кнопка
DrawFocusRect(ScreenDC,MoveRect); //Стираем рамку
Left := Left+X-OldLeft;//Устанавливаем новое левое положение окна
Top := Top+Y-OldTop; //Устанавливаем новое верхнее положение окна
ReleaseDC(0,ScreenDC);// Уничтожаем контекст устройства
Dragging := False; // Перемещение закончено.
end;
Всё, что здесь происходит ты сможешь разобраться по комментариям. Скажу только, что когда мы создавали контекст устройства (GetDC), мы выделили память. Любую память нужно освобождать после использования, для этого мы воспользовались процедурой ReleaseDC.