Delphi 3. Библиотека программиста

Перемещение элементов


Хотя перемещать элементы во время выполнения программы можно несколькими способами, для наших целей лучше всего подойдет трюк с почти недокументированным сообщением WM_SYSCOMMAND. Для перемещения элемента класса TWinControl следует вызвать ReleaseCapture и послать элементу сообщение WM_SYSCOMMAND, указав в качестве параметра wParam шестнадцатеричное значение $F012. А теперь то же самое на языке программы:

ReleaseCapture;

SendMessage(TWinControl(SizingRect1).Handle, WM_SysCommand,

$F012, 0);

Рис. 12.2. Перемещение кнопки Windows

Результат этого фрагмента с точки зрения пользователя изображен на рис. 12.2.

Внешне все выглядит, как при перемещении модального диалогового окна — тонкий пунктирный контур элемента следует за курсором, пока не будет отпущена кнопка мыши.

Возможно, вы уже заметили, что этот способ обладает одним ограниче нием — для него необходим логический номер окна. У потомков TWinControl он имеется, у потомков TGraphicControl — нет. Следовательно, для компонентов типа TGraphicControl (например, TLabel) он работать не будет. Чтобы наши динамические формы были действительно полезными и полноценными, необходимо найти способ перемещения потомков TGraphicControl.

Только что описанный механизм WM_SYSCOMMAND


придется усовершенствовать. Конечно, его нельзя использовать для потомков TGraphicControl напрямую, но обходной путь все же существует — мы создадим прозрачный TWinControl и расположим его над перемещаемым элементом.

Когда пользователь выбирает из контекстного меню команду Adjust Size & Position, мы накладываем прозрачный TWinControl поверх выделенного элемента. Пользователь сможет перетащить прозрачный элемент (с помощью сообщения WM_SYSCOMMAND с параметром $F012) так, словно это и есть «выделенный» элемент. Другими словами, когда пользователь щелкает на выделенном элементе и начинает перетаскивать его, на самом деле он перетаскивает наш прозрачный TWinControl. Затем, когда пользователь решит сохранить внесенные изменения (повторно выбрав команду Adjust Size & Position), мы прячем прозрачный TWinControl и программным способом перемещаем «выделенный» элемент в новое место.

В сущности, именно это происходит в Delphi в режиме конструирования. Если присмотреться повнимательнее, вы увидите, что при перетаскивании элемента на самом деле перемещается прозрачный прямоугольник в толстой рамке (см. рис. 12.3).

Рис. 12.3. Перетаскивание в режиме конструирования Delphi

Прозрачный прямоугольник появляется только над перемещаемым элементом. С того момента, когда вы щелкнули на «выделенном» элементе, и до отпускания кнопки мыши прозрачный прямоугольник следует за курсором. При отпускании кнопки мыши прозрачный прямоугольник исчезает, а перемещаемый элемент оказывается в новом месте.

Наш прозрачный потомок TWinControl называется SizingRect и принадлежит классу TSizingRect. Объект класса TSizingRect заменяет элемент на время перетаскивания.

Важнейшие методы класса TSizingRect — CreateParams и Paint. Метод Create Params определяет некоторые аспекты поведения элемента еще до его создания. Мы воспользуемся этим методом, чтобы сделать наш элемент прозрачным (см. листинг 12.1).

Листинг 12.1. Метод TSizingRect.CreateParams

procedure TSizingRect.CreateParams(var Params: TCreateParams); begin inherited CreateParams(Params); Params.ExStyle := Params.ExStyle + WS_EX_TRANSPARENT; end;

Метод Paint (см. листинг 12.2) рисует толстую рамку, которую видят наши пользователи при перетаскивании SizingRect. При рисовании прямоугольника толщиной в 3 пикселя мы задаем свойству Pen.Mode холста значение pmNot. Тем самым гарантируется, что цвет нарисованного прямоугольника будет отличаться от цвета формы (как и при масштабировании элементов в Delphi).

Листинг 12.2. Метод TSizingRect.Paint

procedure TSizingRect.Paint; begin inherited Paint; if fVisible = False then Exit; Canvas.Pen.Mode := pmNot; Canvas.Pen.Width := 3; Canvas.Brush.Style := bsClear; Canvas.Rectangle(0, 0, Width, Height); end;

Содержание раздела