Code:

{type

  {: Callback to use to copy the data of a treenode when the

    node itself is copied by CopySubtree.

  @param oldnode is the old node

  @param newnode is the new node

  @Desc Use a callback of this type to implement your own algorithm

    for a node copy. The default just uses the Assign method, which

    produces a shallow copy of the nodes Data property. }

  TCopyDataProc = procedure(oldnode, newnode : TTreenode);

 

{: The default operation is to do a shallow copy of the node, via

Assign. }

procedure DefaultCopyDataProc(oldnode, newnode : TTreenode);

begin

  newnode.Assign(oldnode);

end;

 

{-- CopySubtree

-------------------------------------------------------}

{: Copies the source node with all child nodes to the target treeview.

@Param sourcenode is the node to copy

@Param target is the treeview to insert the copied nodes into

@Param targetnode is the node to insert the copy under, can be nil to

make the copy a top-level node.

@Param CopyProc is the (optional) callback to use to copy a node.

If Nil is passed for this parameter theDefaultCopyDataProc will be

used.

@Precondition  sourcenode <> nil, target <> nil, targetnode is either

nil or a node of target

@Raises Exception if targetnode happens to be in the subtree rooted in

sourcenode. Handling that special case is rather complicated, so we

simply refuse to do it at the moment.

}{ Created 2003-04-09 by P. Below -----------------------------------------------------------------------

}

procedure CopySubtree(sourcenode : TTreenode; target : TTreeview;

  targetnode : TTreenode; CopyProc : TCopyDataProc = nil);

var

  anchor : TTreenode;

  child : TTreenode;

begin { CopySubtree }

  Assert(Assigned(sourcenode),

    'CopySubtree:sourcenode cannot be nil');

  Assert(Assigned(target),

    'CopySubtree: target treeview cannot be nil');

  Assert((targetnode = nil) or (targetnode.TreeView = target),

    'CopySubtree: targetnode has to be a node in the target treeview.');

 

  if (sourcenode.TreeView = target) and

    (targetnode.HasAsParent(sourcenode) or (sourcenode =

    targetnode)) then

    raise Exception.Create('CopySubtree cannot copy a subtree to one of the ' +

      'subtrees nodes.');

 

  if not Assigned(CopyProc) then

    CopyProc := DefaultCopyDataProc;

 

  anchor := target.Items.AddChild(targetnode, sourcenode.Text);

  CopyProc(sourcenode, anchor);

  child := sourcenode.GetFirstChild;

  while Assigned(child) do

   begin

    CopySubtree(child, target, anchor, CopyProc);

    child := child.getNextSibling;

  end; { While }

end; { CopySubtree }

 

 

procedure TForm1.Button1Click(Sender : TObject);

begin

  if assigned(treeview1.selected) then

    CopySubtree(treeview1.selected, treeview2, nil);

end;

Code:

unit BetterTreeView;

 

interface

 

uses

Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs,

ComCtrls, CommCtrl;

 

type

TTVNewEditCancelEvent = procedure( Sender: TObject;

   Node: TTreeNode; var Delete: Boolean) of object;

TBetterTreeView = class(TTreeView)

protected

   FIsEditingNew: Boolean;

   FOnEditCancel: TTVChangedEvent;

 

   FOnNewEditCancel: TTVNewEditCancelEvent;

   procedure Edit(const Item: TTVItem); override;

public

   function NewChildAndEdit(Node: TTreeNode; const S: String)

     : TTreeNode;

published

   property IsEditingNew: Boolean read FIsEditingNew;

   property OnEditCancel: TTVChangedEvent

     read FOnEditCancel write FOnEditCancel;

   property OnNewEditCancel: TTVNewEditCancelEvent

     read FOnNewEditCancel write FOnNewEditCancel;

end;

 

implementation

 

procedure TBetterTreeView.Edit(const Item: TTVItem);

var

Node: TTreeNode;

Action: Boolean;

begin

with Item do begin

   { Get the node }

   if (state and TVIF_PARAM) <> 0 then

     Node := Pointer(lParam)

   else

     Node := Items.GetNode(hItem);

 

   if pszText = nil then begin

     if FIsEditingNew then begin

       Action := True;

       if Assigned(FOnNewEditCancel) then

         FOnNewEditCancel(Self, Node, Action);

       if Action then

 

         Node.Destroy

     end

     else

       if Assigned(FOnEditCancel) then

         FOnEditCancel(Self, Node);

   end

   else

     fFinherited;

end;

FIsEditingNew := False;

end;

 

function TBetterTreeView.NewChildAndEdit

(Node: TTreeNode; const S: String): TTreeNode;

begin

SetFocus;

Result := Items.AddChild(Node, S);

FIsEditingNew := True;

Node.Expand(False);

Result.EditText;

SetFocus;

end;

 

end.

 

Code:

{

Treeview1.SaveToFile('...') doesn't store images.

Instead, use the code below.

}

 

 

// Save

 

procedure TForm1.Button1Click(Sender: TObject);

var

  F: TFileStream;

begin

  F := TFileStream.Create('c:\TreeView.txt', fmCreate or fmShareCompat);

  try

    F.WriteComponent(TreeView1);

  finally

    F.Free;

  end;

end;

 

 

// Load

 

procedure TForm1.Button2Click(Sender: TObject);

var

  F: TFileStream;

begin

  F := TFileStream.Create('c:\TreeView.txt', fmOpenRead or fmShareDenyWrite);

  try

    F.ReadComponent(TreeView1);

  finally

    F.Free;

  end;

end;

 

 

Code:

uses

  ComCtrls, Menus, Classes, Forms, Controls, Windows, Messages;

 

function GetControlCaption(Control: TWinControl): ShortString;

  //  Slightly modified version of Twister's Tip

//

//  function GetCaptionAtPoint(pt: TPoint): string;

//

var

  TextLength: Integer;

  Text: PChar;

begin

  if not Boolean(Control.Handle) then Exit;

 

  Result := Control.Name//  if Control doesn't have Caption

//  Control.Name is returned

 

TextLength := SendMessage(Control.Handle, WM_GETTEXTLENGTH, 0, 0);

  if TextLength  0 then

  begin

    GetMem(Text, TextLength + 1);

    SendMessage(Control.Handle, WM_GETTEXT, TextLength + 1, Integer(Text));

    Result := Text;

    FreeMem(Text);

  end;

end;

 

//  function GetCaptionAtPoint(pt: TPoint): ShortString;

//  begin

//    Result:= GetControlCaption(FindVCLWindow(pt));

//  end;

 

 

procedure FindAllMenuItems(AppTree: TTreeView; MenuItem: TMenuItem; Parent: TTreeNode);

var

  loop: Integer;

  Node: TTreeNode;

  mItem: TMenuItem;

  Name: ShortString;

begin

  for loop := 0 to MenuItem.Count - 1 do

  begin

    mItem := MenuItem.Items[loop];

    Name := mItem.Caption;

    Node  := AppTree.Items.AddChildObject(Parent, Name, mItem);

    if mItem.Count  0 then findAllMenuItems(AppTree, mItem, Node);

  end;

end;

 

procedure FindAllControls(AppTree: TTreeView; Comp: TComponent; Parent: TTreeNode);

var

  Child: TComponent;

  loop, start, Index: Integer;

  Name: ShortString;

  Node, Mnode: TTreeNode;

begin

  start := 0;

  if Comp is TApplication then

  begin

    // Parent:= AppTree.Items.AddObjectFirst(Parent, 'Application', nil);

   //  if you want to see the root ('Application') uncomment

   start := 1;

  end;

 

  for loop := start to Comp.ComponentCount - 1 do

  begin

    Child := Comp.Components[loop];

    Name := Child.Name;

 

    if Child is TControl then

    begin

      if Child is TWinControl then

      begin //  does Child have Caption property??

       Name := GetControlCaption(TWinControl(Child));

      end;

      Node := AppTree.Items.AddChildObject(Parent, Name, Child);

      if Child.ComponentCount  0 then FindAllControls(AppTree, Child, Node);

    end;

 

    if Child is TMenu then

    begin

      Node := AppTree.Items.AddChildObject(Parent, Name, Child);

      for Index := 0 to TMenu(Child).Items.Count - 1 do

      begin

        Mnode := AppTree.Items.AddChildObject(Node, TMenu(Child).Items[Index].Caption,

          TMenu(Child).Items[Index]);

        FindAllMenuItems(AppTree, TMenu(Child).Items[Index], Mnode);

      end;

    end;

  end;

end;

 

Представляем вашему вниманию немного переработанный компонент TreeView, работающий быстрее своего собрата из стандартной поставки Delphi. Кроме того, была добавлена возможность вывода текста узлов и пунктов в жирном начертании (были использованы методы TreeView, хотя, по идее, необходимы были свойства TreeNode. Мне показалось, что это будет удобнее).

 

Для сравнения:

 

TreeView:

 

128 сек. для загрузки 1000 элементов (без сортировки)*

270 сек. для сохранения 1000 элементов (4.5 минуты!!!)

HETreeView:

 

Автор: Mike Scott

 

На пустой форме у меня располагается TTreeView. Затем я сохраняю это в файле, используя WriteComponent. Это работает как положено; я могу из DOS c помощью команды "type" посмотреть двоичный файл и увидеть его содержимое, типа строк TTreeView и имя объекта. По крайней мере файл записывается и создается впечатление его "наполненности".

 

Затем я освобождаю компонент TTreeView, открываю поток, делаю ReadComponent и, затем, InsertControl. И получаю исключение "TreeView1 has no parent window" (TreeView1 не имеет родительского окна).

 

 

Code:

function IsTreeviewFullyExpanded(tv: TTreeview): Boolean;

var

  Node: TTreeNode;

begin

  Assert(Assigned(tv));

  if tv.Items.Count > 0 then

  begin

    Node   := tv.Items[0];

    Result := True;

    while Result and Assigned(Node) do

    begin

      Result := Node.Expanded or not Node.HasChildren;

      Node   := Node.GetNext;

    end; {While}

  end {If}

  else

    Result := False

end;

 

function IsTreeviewFullyCollapsed(tv: TTreeview): Boolean;

var

  Node: TTreeNode;

begin

  Assert(Assigned(tv));

  if tv.Items.Count > 0 then

  begin

    Node   := tv.Items[0];

    Result := True;

    while Result and Assigned(Node) do

    begin

      Result := not (Node.Expanded and Node.HasChildren);

      Node   := Node.GetNext;

    end; {While}

  end {If}

  else

    Result := False

end;

 

 

Code:

// Search a TreeItem through its Text property

// Return value is a TreeNodeObject

function Form1.TreeItemSearch(TV: TTreeView; SucheItem: string): TTreeNode;

var

i: Integer;

iItem: string;

begin

if (TV = nil) or (SucheItem = '') then Exit;

for i := 0 to TV.Items.Count - 1 do

begin

   iItem := TV.Items[i].Text;

   if SucheItem = iItem then

   begin

     Result := TV.Items[i];

     Exit;

   end

   else

   begin

     Result := nil;

   end;

end;

end;

 

Нужно использовать рекурсивные механизмы спуска по дереву и иметь метод определения наличия child узлов у текущего узла.

 

Code:

function TDBTreeView.RecurseChilds(node: TTreeNode): double;

begin

while node <> nil do begin

   if node.HasChildren then

      Result := RecurseChilds(node.GetFirstChild);

   Result := Result + GetResultForNode(node));

   node := node.GetNextSibling;

end;

end;

 

function TDBTreeView.GetResult(curnode: TTreeNode;): double;

begin

Result := 0;

if curnode = nil then Exit;

Result := RecurseChilds(curnode.GetFirstChild);

end;

 

Code:

{ **** UBPFD *********** ****

>> Получение узла в TreeView по пути заголовков

 

Функция выдает узел TTreeNode из дерева TreeView, находящийся по пути,

указанному в Path, в котором разделителем уровней является символ Separator.

Если узел не найден - выдается nil.

Ограничение - заголовки узлов дерева не должны содержать символа Separator.

 

Зависимости: ComCtrls, Classes, SysUtils

Автор:       lipskiy, Этот адрес электронной почты защищён от спам-ботов. У вас должен быть включен JavaScript для просмотра., ICQ:51219290, Санкт-Петербург

Copyright:   Собственное написание (lipskiy)

***************************************************** }

 

function GetNodeInPath(Path: string; Separator: char; TreeView: TTreeView):

TTreeNode;

var

List: TStringList;

Node: TTreeNode;

i: integer;

s: string;

begin

Result := nil;

if (TreeView = nil) or (TreeView.Items.Count = 0) or (Path = '') or (Separator

   = '') then

   exit;

List := TStringList.Create;

// Меняем сепаратор на первод строки

s := StringReplace(Path, Separator, #13#10,[rfReplaceAll]);

// Получаем список уровней

List.Text := s;

// Начинаем с нулевой ноды дерева

Node := TreeView.Items[0];

// Проходим по всему списку уровней пути

for i := 0 to List.Count - 1 do

begin

   // Ищем имя ноды на текущем уровне

   while (Node <> nil) and (Node.Text <> List[i]) do

     Node := Node.getNextSibling;

   // Нода не найдена

   if Node = nil then

     break;

   // Переходим на уровень ниже

   if i < List.Count - 1 then

     Node := Node.getFirstChild;

end;

List.Free;

Result := Node;

end;

 

// Пример использования:

procedure TForm1.Button1Click(Sender: TObject);

begin

TreeView1.Selected := GetNodeInPath('Каталог\Подкаталог', '\', TreeView1);

end;