Рассмотрим реализацию в
своих программах такой функции как 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); } } | |