Проще всего делать Drag из тех компонентов, для которых однозначно ясно, что именно перетаскивать. Для этого устанавливаем у источника DragMode = dmAutomatic, а у приемника пишем обработчики событий OnDragOver - разрешение на прием, и OnDragDrop - действия, производимые при окончании перетаскивания.
Код:
procedure TForm1.StringGrid2DragOver(Sender, Source: TObject; X,
Y: Integer; State: TDragState; var Accept: Boolean);
begin
Accept := Source = Edit1;
// разрешено перетаскивание только из Edit1,
// при работе программы меняется курсор
end;
procedure TForm1.StringGrid2DragDrop(Sender, Source: TObject; X,
Y: Integer);
var
ACol, ARow: Integer;
begin
StringGrid2.MouseToCell( X, Y, ACol, ARow);
// находим, над какой ячейкой произвели Drop
StringGrid2.Cells[ Acol, Arow] := Edit1.Text;
// записываем в нее содержимое Edit1
end;
Теперь рассмотрим копирование в упорядоченный список ListBox1 из другого списка. В OnDragOver проверяем, выбран ли хоть один элемент в источнике:
Код:
Accept := (Source = ListBox2) and (ListBox2.ItemIndex >= 0);
В OnDragDrop ищем отмеченные в источнике строки (установлен множественный выбор) и добавляем только те, которых еще нет в приемнике:
Код:
for i := 0 to ListBox2.Items.Count - 1 do
if (ListBox2.Selected[i]) and (ListBox1.Items.IndexOf(ListBox2.Items[i])<0)
then
ListBox1.Items.Add(ListBox2.Items[i]);
Для ListBox2 реализуем перенос строк из ListBox1 и перестановку элементов в желаемом порядке. В OnDragOver разрешаем Drag из любого ListBox:
Код:
Accept := (Source is TListBox) and ((Source as TListBox).ItemIndex >= 0);
А OnDragDrop будет выглядеть так:
Код:
var
s: string;
begin
if Source = ListBox1 then
begin
ListBox2.Items.Add(ListBox1.Items[ListBox1.ItemIndex]);
ListBox1.Items.Delete(ListBox1.ItemIndex);
//удаляем перенесенный элемент
end
else //внутренняя перестановка
begin
s := ListBox2.Items[ListBox2.ItemIndex];
ListBox2.Items.Delete(ListBox2.ItemIndex);
ListBox2.Items.Insert(ListBox2.ItemAtPos(Point(X, Y), False), s);
//находим, в какую позицию переносить и вставляем
end;
end;
Научимся переносить текст в Memo, вставляя его в нужное место. Поскольку я выбрал в качестве источника любой из ListBox, подключим в Инспекторе Объектов для OnDragOver уже написанный ранее обработчик ListBox2DragOver, а в OnDragDrop напишем
Код:
if not CheckBox1.Checked then // при включении добавляется в конец текста
begin
Memo1.SelStart := LoWord(Memo1.Perform(EM_CHARFROMPOS, 0, MakeLParam(X,Y)));
// устанавливаем позицию вставки согласно координатам мыши
Memo1.SelText := TListBox(Source).Items[TListBox(Source).ItemIndex];
end
else
memo1.lines.add(TListBox(Source).Items[TListBox(Source).ItemIndex]);
Замечу, что для RichEdit EM_CHARFROMPOS работает несколько иначе, что продемонстрировано в следующем примере. Перенос из Memo реализован с помощью правой кнопки мыши, для того, чтобы не изменять стандартное поведение Memo, и поскольку нажатие левой кнопки снимает выделение. Для Memo1 установлено DragMode = dmManual, а перетаскивание инициируется в OnMouseDown
Код:
if (Button = mbRight) and (Memo1.SelLength > 0) then Memo1.BeginDrag(True);
Обработчик RichEdit1DragOver очевиден, а в RichEdit1DragDrop пишем
Код:
var
p: tpoint;
begin
if not CheckBox1.Checked then
begin
p := point(x, y);
RichEdit1.SelStart := RichEdit1.Perform(EM_CHARFROMPOS, 0, Integer(@P));
RichEdit1.SelText := Memo1.SelText;
end
else
RichEdit1.Lines.Add(Memo1.SelText);
end;