Добрый вечер,
Перемещение контрола можно сделать двумя способами:
Используя обычный набор событий OnMouseDown, OnMouseMove, OnMouseUp.
Использовать для перемещения жесты.
1. Реализация с использованием событий мыши
Эти события реализованы для всех платформ. В том числе они эмулируются на мобильных платформ, где понятия мыши, как такового нету. Это означает, что их можно использовать для реализации перетаскивания контрола. Это можно сделать, например, следующим образом:
а) Создаем форму и кидаем на нее картинку. Я назвал ее DraggableImage. б) Заводим два поля.
TForm5 = class(TForm)
DraggableImage: TImage;
procedure DraggableImageMouseDown(Sender: TObject; Button: TMouseButton; Shift: TShiftState; X, Y: Single);
procedure DraggableImageMouseMove(Sender: TObject; Shift: TShiftState; X, Y: Single);
procedure FormCreate(Sender: TObject);
procedure DraggableImageMouseUp(Sender: TObject; Button: TMouseButton; Shift: TShiftState; X, Y: Single);
private
FStartPos: TPointF;
FPressed: Boolean;
end;
FStartPos - начальная локальная позиция мыши внутри нашего контрола (картинки), когда пользователь зажал кнопку мышки или опустил палец на экран.
FPressed - флаг для сигнализирования, что пользователь опустил палец (зажал кнопку мыши) на нашу картинку и до текущего момента не снял с экрана.
в) В конструкторе формы для перетаскиваемого контрола ОБЯЗАТЕЛЬНО задаем AutoCapture = True. Это позволит контролу генерировать события перемещения мыши, даже если курсор мыши ушел за локальные границы контрола.
procedure TForm5.FormCreate(Sender: TObject);
begin
DraggableImage.AutoCapture := True;
end;
г) В момент нажатия на картинку сохраняем локальную позицию мыши и задаем флаг FPressed = True
procedure TForm5.DraggableImageMouseDown(Sender: TObject; Button: TMouseButton; Shift: TShiftState; X, Y: Single);
begin
FPressed := True;
FStartPos := TPointF.Create(X, Y);
end;
д) В момент отпускания кнопки мыши или убирания пальца с экрана сбрасываем флаг FPressed:
procedure TForm5.DraggableImageMouseUp(Sender: TObject; Button: TMouseButton; Shift: TShiftState; X, Y: Single);
begin
FPressed := False;
end;
е) И собственно меняем позицию картинки, когда мы ведем мышкой по картинке:
procedure TForm5.DraggableImageMouseMove(Sender: TObject; Shift: TShiftState; X, Y: Single);
var
MoveVector: TVector;
begin
if FPressed then
begin
// Вычисляем локальное смещение относительно первоначальной позиции
MoveVector := TVector.Create(X - FStartPos.X, Y - FStartPos.Y, 0);
// Вычисляем смещение в координатах формы, чтобы учесть изменение
// координат при смещении родительских контролов
MoveVector := DraggableImage.LocalToAbsoluteVector(MoveVector);
if DraggableImage.ParentControl <> nil then
MoveVector := DraggableImage.ParentControl.AbsoluteToLocalVector(MoveVector);
// Перемещаем картинку на вычисленный вектор
// Для RAD Studio XE5
DraggableImage.Position.Point := DraggableImage.Position.Point + MoveVector.ToPointF;
// Для новых версий
// DraggableImage.Position.Point := DraggableImage.Position.Point + TPointF(MoveVector);
end;
end;
Этот кусок стоит прокомментировать, чтобы корректно выполнить перетаскивание контролу обязательно нужно вычислять смещение в абсолютных координатах формы. Причина в том, что если контрол повернут или входит один в другой, то нужно учитывать смещения всей цепочки родительских контролов до формы. Поэтому мы вначале вычисляем смещение в локальных координатах, затем вычисляем его в абсолютных координатах формы. А затем обратно переводим в локальные координаты родительского контрола. После чего изменяем позицию контрола на вычисленное смещение.
Такой подход используется, в частности, в контроле TSelection, который так же можно перемещать мышкой или пальцем.
P.S. Чтобы лучше понять это, нарисуйте на листке бумаги положения контрола и попробуйте вручную выполнить этот алгоритм с преобразованием координат.
Собственно говоря, такой подход отлично работает везде и не требует использования системы жестов.
2. Реализация с использованием жестов
Этот способ будет работать только на мобильных платформах, поскольку нужный жест Pan (если я правильно помню) не поддерживается под Windows. Поэтому в целом, первый вариант является универсальным и лучшим решением.