Реализация Drag and Drop в списках C++ Builder
Рассмотрим реализацию в своих программах такой
функции как Drag and Drop. Для опытов создадим форму, содержащую два
объекта TListBox и объект TLabel. Для поддержки
перетаскивания объекты должны обрабатывать два события. Первое - событие
OnDragDrop, возникающее, когда вы роняете что-нибудь на объект.
Второе событие - OnDragOver. Обработчик этого события вызывается
для проверки корректности перетаскиваемых данных. Если это событие не
обрабатывать, то курсор перетаскивания над объектом превратится в знак
запрещения. Итак, выделяем оба списка и на закладке Events в Object
Inspector выбираем событие OnDragOver. После двойного щелчка на нем
вводим следующий код:
void __fastcall TForm1::ListBox1DragOver(TObject *Sender,
TObject *Source, int X, int Y, TDragState State, bool
&Accept) { Accept =
true; } |
Данный код просто сообщает, что списки способны
воспринимать перетаскивание. Вообще-то в этом обработчике можно (и нужно)
отсекать данные, нам не предназначающиеся (и устанавливать в таком случае
Accept = false), но в нашем небольшом примере не будем рассматривать такие
случаи. Теперь напишем обработчик события
OnDragDrop. Он выполняется, когда вы притащите что-нибудь на один
из списков.
void __fastcall TForm1::ListBox1DragDrop(TObject
*Sender, TObject *Source, int X, int
Y) { TListBox *pListSource = (TListBox
*)Source; TListBox *pListDest = (TListBox
*)Sender;
for (int i=0;
i<pListSource->Items->Count;
++i) if
(pListSource->Selected[i]) { pListDest
-> Items ->
Add(pListSource->Items->Strings[i]); pListSource->Items->Delete(i); } }
|
Да, забыли про наш объект TLabel. Он у нас
будет служить для индикации текущего состояния перетаскивания. Когда мы
только начинаем перетаскивать данные, или когда отпускаем кнопку мыши,
возникают соответственно два события - OnStartDrag и
OnEndDrag. В нашем случае не будем слишком перегружать обработчики
этих событий (а использовать их можно для проверки совместимости или
правильности перетаскиваемых данных и т.п.), а просто напишем:
void __fastcall TForm1::ListBox1StartDrag(TObject *Sender,
TDragObject *&DragObject) { Label1 ->
Caption = "Начинаем перетаскивание..."; }
void __fastcall
TForm1::ListBox1EndDrag(TObject *Sender, TObject *Target, int X, int
Y) { Label1 -> Caption = "Закончили
перетаскивание"; } |
Собственно, все. Проверьте, что свойство
DragMode установлено в dmAutomatic. Если хотите, чтобы
перетаскивались сразу несколько выделенных строк списка, установите
свойство MultiSelect в true. И напоследок, неплохо бы добавить
элементы, которые мы будем перетаскивать. Для этого введите несколько
строк (любых) в свойствах Items списков. Можно компилировать
проект. Отметим несколько неочевидных вещей: первое
- код работает для обоих списков одинаково, т.е. оба списка могут служить
как источниками, так и приемниками; второе - код работает даже для одного
и того же источника и приемника (когда мы перетаскиваем объект на тот же
список, откуда его и взяли). А теперь несколько
усложним задачу. Как вы заметили, перетащенный объект появляется в конце
списка, что не всегда удобно. Изменим обработчик события OnDragDrop таким
образом, чтобы объект помещался именно в то место списка, куда мы
указываем мышью. Код будет выглядеть следующим образом:
void __fastcall TForm1::ListBox1DragDrop(TObject
*Sender, TObject *Source, int X, int
Y) { TListBox *pListSource = (TListBox
*)Source; TListBox *pListDest = (TListBox
*)Sender; POINT p;
p.x = X; p.y =
Y; int nItemIndex = pListDest ->
ItemAtPos(p, false);
for (int i=0;
i<pListSource->Items->Count;
++i) if
(pListSource->Selected[i]) { pListDest
-> Items -> Insert(nItemIndex,
pListSource->Items->Strings[i]); pListSource->Items->Delete(i); } }
|
Вот так все просто... Вы можете скачать архив с проектом для C++Builder 5.0.
|