Сегодня рассмотрим такую интересную вещь, как Drug and Drop - "Перетащи и отпусти". Возможно, вы уже слышали о данной технологии, которая позволяет перемещать объекты зажатием на них мыши. Например, в проводнике Windows мы с лёгкостью можем зажать курсором файл, перетащить его и скинуть в какой-либо дирректории. Или, как второй пример, можно привести панель задач windows. Мы можем перенести на неё какую-либо иконку и она останется закреплена на ней. Вот эти действия и представляют собой технологию Drug and Drop. Давайте рассмотрим, как она работает.
ТЕОРИЯ.
Для начала нужно сказать, что почти у всех визуальных компонентов (кнопки, панели, list-box'ы, etc) имеются описанные события, благодаря которым можно реализовать данную технологию. Рассмотрим эти события:
1) OnStartDrag:
Инициатором события выступает объект-источик, генерируется в начале операции перетаскивания. Событие имеет 2 параметра:
1) Объект приемник (грубо говоря, проводя аналогию, объект-приемник в случае с проводником windows является дирректория, куда мы скидываем объект, т.е. эта дирректория ПРИНИМАЕТ зажатый нами объект.) - DragObject: TDragObject
2) Объект источник (Объект, который мы перетаскиваем) - Sender: TObject
2) OnDragOver:
Событие генерируется объектом-приемником, возникается в тот момент, когда объект под курсором мыши двигается над объектом-приемником. Событие имеет 6 параметров:
1) Sender: TObject - Ссылка на объект-приемник
2) Source: TObject - Ссылка на объект-источник
3,4) X,Y: Integer - Координаты текущего указателя мыши
5) State (dsDragEnter - Указатель появился над приёмником; dsDragLeave - Указатель убран с поверхности объекта-приемника; dsDragMove - Указатель движется над приёмником)
6) Accept: Boolean - Признак подтверждения операции перемещения (если операция прошла успешно - TRUE, иначе - FALSE)
3) OnDragDrop:
Событие генерирует элемент-приемник, возникает оно при отпускании мыши. Если параметр Accept, полученный в событии OnDragOver имеет значение True, то элемент-источник успешно ляжет на элемент-приемник. Событие имеет 4 параметра:
1,2) Sender, Source: TObject - описаны выше;
2,3) X, Y: integer - так же аналогичны событиям, описанным в событии DragOver.
4) OnEndDrag - Вне зависимости от того, приняла ли переменная Accept значение True (можно передать элемент) или осталась ли она False (запрет на передачу элементов) - сгенерируется это событие, инициатором выступает объект-источник. Параметры (Sender, Target: TObject; X,Y: integer;) полносью аналогичный описанным выше. Стоит сказать, что в данном случае параметр Target - объект-приемник.
События представлены именно в том порядке, в котром они будут генерироваться во время операции перетаскивания.
ПРАКТИКА.
Наконец-то закончили с теорией, приступим уже к кодингу. Первым делом, нужно выбрать, что будем перетаскивать. В моём случае - это будут 2 ListBox'а (перемещать, разумеется, будем строки в них).
Форма:
Ну и не менее важное занятие - настроить свойства. Их, для Drag and Drop, 2:
1) DragKind (dkDrag или dkLock):
dkDrag - разрешает Drag and Drop; dkLock - блокирует Drag and Drop.
2) DragMode (dmManual или dmAutomatic) - режим работы Drag and Drop. Говоря про Automatic режим - тут тоже нужно описывать свойства, но не все, а 2. При этом программа сама будет генерировать остальные. В нашем случае нужно выбрать dmManual, т.к. нам нужно запоминать строки и передавать их от компонента-источника к компоненту-приемнику.
У каждого из List-box'ов пишем почти аналогичный код в следующих свойствах:
OnMouseMove:
begin
if (listbox1.ItemIndex <> -1) and ( ssLeft in Shift ) then //Если нажата левая кнопка мыши (ssLeft in Shift) и выделенна строка, то
listbox1.BeginDrag(False,8); //Начинаем операцию Drag (перетаскивание)
end;
Прописываем переменную i в раздел приватных переменных (private) и продолжаем.
OnStartDrag:
begin
i:= listbox1.ItemIndex; // Запоминаем номер у выделенной строки
end;
OnDragOver:
begin
Accept:= (i <> -1) and (Sender<> Source); // Accept = true, если переменная i запомнила выделенную строку и объект-приеник не является объектом-источником.
end;
Последним действием мы выполнили свою основную задачу - передали программе, можно ли ей перемещать объект или нет.
OnDragDrop:
var
строка: string;
begin
{Передаём строку из списка Sourse в список Sender}
строка:= listBox1.Items.Strings[Index]; // ложим в переменную нужную строку
listbox2.Items.Add(строка); // передаём ей в объект-приемник (в нашем случае второй listbox)
listBox1.Items.Delete(I); // удаляем перемещённую строку из первого источника
end;
OnEndDrag:
begin
I:= -1; // Выставим переменной ложное значение по завершению операции
end;
Проверим?
1) Захватили объект (строку) с компонента-источника (1-ый listbox) и потащали объект (обратите внимание на курсор):
2) Навели объект на компонент-приёмник (второй объект):
3) Отпустили объект, он удалился из listbox1 и появился в listbox2:
Спасибо за внимание.