Показать сообщение отдельно
  #3  
Старый 20.07.2007, 12:03
Аватар для 4kusNick
4kusNick 4kusNick вне форума
Местный
 
Регистрация: 06.09.2006
Адрес: Россия, Санкт-Петербург
Сообщения: 444
Репутация: 550
По умолчанию

Рассмотрим теперь перетаскивание в 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;
__________________
THE CRACKER IS OUT THERE
Ответить с цитированием