Спасибо, Джон. При перетаскивании объекта в Delphi вид курсора изменяется; по умолчанию курсор принимает вид стрелки, к которой присоединена небольшая рамка. Такое визуальное обозначение перетаскивания выглядит вполне нормально — раз уж курсор присутствует на экране, почему бы ему не выглядеть именно так?
Тем не менее вы можете придать пользователям еще больше уверенности в происходящем. Например, при перетаскивании одной из строк списка курсорможет выглядеть как прозрачное изображение текста, окруженное пунктирным прямоугольником. Оказывается, в Delphi 3 сделать это несложно.В листинге 9.5 приведен полный исходный текст компонента-списка, обладающего такой возможностью.
В отличие от Delphi 1 версии Delphi 2 и Delphi 3 обладают встроенной поддержкой для перетаскивания графических элементов; все, что от вас требуется — предоставить нужное изображение. Для этого следует нарисовать его в растровом виде, поместить растр в компонент TImageList и передать этот объект Delphi. После этого за перерисовку изображения при перемещении мыши будет отвечать код Delphi из модуля Controls.
Как видно из листинга 9.5, для хранения графики используется private-поле типа TImageList. Его следует создать как можно раньше, но не заносить в него изображение до начала перетаскивания. Чтобы обнаружить начало операции перетаскивания, мы переопределяем метод DoStartDrag. Кроме того, необходимо переопределить и метод GetDragImages, поскольку список изображе ний передается Delphi именно при вызове этого метода.
Почему мы не рисуем изображение сразу, а ждем до последней секунды? Потому что это позволяет синхронизировать перетаскиваемое изображение с перетаскиваемым элементом. Как узнать, какой текст следует вывести в растре, если еще неизвестно, какой элемент списка перетаскивается?
Листинг 9.5. Модуль TXTDRGBX.PAS
unit TxtDrgBx; interface uses Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs, StdCtrls, ExtCtrls; type TTextDragListBox = class( TListBox ) private FDragImage: TImageList; protected procedure CreateDragImage; procedure DoStartDrag( var DragObject: TDragObject ); override; public constructor Create( AnOwner: TComponent ); override; destructor Destroy; override; function GetDragImages: TCustomImageList; override; end; procedure Register; implementationОсновную часть листинга 9.5 занимает процедура CreateDragImage для работы со списком изображений. После создания и прорисовки растра размер списка изображений приводится в соответствие с размером растра (не забывайте это делать!), после чего метод AddMasked заносит растр в список и назначает прозрачный цвет.
Метод SetDragImage, вызываемый двумя строками ниже, задает положение активной точки (hotspot) перетаскиваемого изображения. Мышь «держит» перетаскиваемое изображение в активной точке. В нашем случае вызов SetDragImage гарантирует, что текстовый прямоугольник будет перетаскиваться за точку его первоначального «захвата».
Конечно, запрограммировать этот прием в Delphi 2 и 3 оказывается сложнее, чем просто рисовать на экране, но зато перед вами открываются широкие возможности для организации визуального взаимодействия компонентов. Например, при перетаскивании изображения между списками второй список может скрыть перетаскиваемое изображение, выделить свой элемент-приемник и затем вернуть скрытое изображение на экран.