Рассмотрим теперь перетаскивание в ListView1 (ViewStyle = vsReport). В OnDragOver разрешим прием из ListBox2 и из себя же:
Код:
Accept := ((Source = ListBox2) and (ListBox2.ItemIndex >= 0)) or
(Source = Sender);
А вот OnDragDrop теперь будет посложнее
Код:
var
Item, CurItem: TListItem;
begin
if Source = ListBox2 then
begin
Item := ListView1.DropTarget;
if Item <> nil then
// случай перетаскивания на Caption
if Item.SubItems.Count = 0 then
Item.SubItems.Add(ListBox2.Items[ListBox2.ItemIndex])
// добавляем SubItem, если их еще нет
else
Item.SubItems[0]:=ListBox2.Items[ListBox2.ItemIndex]
// иначе заменяем имеющийся SubItem
else
begin
// при перетаскивании на пустое место создаем новый элемент
Item := ListView1.Items.Add;
Item.Caption := ListBox2.Items[ListBox2.ItemIndex];
end;
end
else // случай внутренней перестановки
begin
CurItem := ListView1.Selected;
// запомним выбранный элемент
Item := ListView1.GetItemAt(x, y);
// другой метод определения элемента на который делаем Drop
if Item <> nil then
Item := ListView1.Items.Insert(Item.Index)
// вставляем новый элемент перед найденным
else
Item := ListView1.Items.Add;
// или добавляем новый элемент в конец
Item.Assign(CurItem);
// копируем исходный в новый
CurItem.Free;
// уничтожаем исходный
end;
end;
Для ListView2 установим ViewStyle = vsSmallIcon и покажем, как вручную расставлять значки. В OnDragOver зададим условие
Код:
Accept := (Sender = Source) and
([htOnLabel,htOnItem, htOnIcon] * ListView2.GetHitTestInfoAt(x, y) = []);
// пересечение множеств должно быть пустым - запрещаем накладывать элементы
а код в OnDragDrop очень простой:
Код:
ListView2.Selected.SetPosition(Point(X,Y));
Перетаскивание в TreeView - довольно любопытная тема, здесь порой приходится разрабатывать алгоритмы обхода ветвей для достижения желаемого поведения. Для TreeView1 разрешим перестановку своих узлов в другое положение. В OnDragOver проверим, не происходит ли перетаскивание узла на свой же дочерний во избежание бесконечной рекурсии:
Код:
var
Node, SelNode: TTreeNode;
begin
Node := TreeView1.GetNodeAt(x, y);
// находим узел-приемник
Accept := (Sender = Source) and (Node <> nil);
if not Accept then
Exit;
SelNode := Treeview1.Selected;
while (Node.Parent <> nil) and (Node <> SelNode) do
begin
Node := Node.Parent;
if Node = SelNode then
Accept := False;
end;
Код OnDragDrop выглядит так:
Код:
var
Node, SelNode: TTreeNode;
begin
Node := TreeView1.GetNodeAt(X, Y);
if Node = nil then
Exit;
SelNode := TreeView1.Selected;
SelNode.MoveTo(Node, naAddChild);
// все уже встроено в TreeView
end;
Теперь разрешим перенос в TreeView2 из TreeView1
Код:
Accept := (Source = TreeView1) and (TreeView2.GetNodeAt(x, y) <> nil);
И в OnDragDrop копируем выбранную в TreeView1 ветвь во всеми подветвями, для чего придется сделать рекурсивный обход:
Код:
var
Node: TTreeNode;
procedure CopyNode(FromNode, ToNode: TTreeNode);
var
TempNode: TTreeNode;
i: integer;
begin
TempNode := TreeView2.Items.AddChild(ToNode, '');
TempNode.Assign(FromNode);
for i := 0 to FromNode.Count - 1 do
CopyNode(FromNode.Item[i], TempNode);
end;
begin
Node := TreeView2.GetNodeAt(X, Y);
if Node = nil then
Exit;
CopyNode(TreeView1.Selected, Node);
end;