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

 

Программирование | Главная 




Hosted by uCoz