Link to home
Start Free TrialLog in
Avatar of voodoo22
voodoo22

asked on

Using TTreeView

I am pretty new to using the TTreeView component and while I have figued out some of it on my own I still can't seem to find any information on the following things so if one of the experts could help me out it would be great.

1.) How to get the count of items per level (ie. level0 items count = 44   level1 items count = 212...)


2.) How do you load (specific information)from a text file when you click on an node/subnode.
Avatar of voodoo22
voodoo22

ASKER

BTW the information on question 2 would be loaded into a RichEdit Control if that helps.
Avatar of kretzschmar
listening . . . no time yet
Hope this helps a little...

grtz.

//Code

unit Unit1;

interface

uses
  Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
  Dialogs, StdCtrls, ComCtrls, Menus, ExtCtrls;

type
  TForm1 = class(TForm)
    TreeView1: TTreeView;
    Panel1: TPanel;
    RichEdit1: TRichEdit;
    Button2: TButton;
    Button1: TButton;
    procedure Button1Click(Sender: TObject);
    procedure Button2Click(Sender: TObject);
    procedure FormCreate(Sender: TObject);
    procedure FormDestroy(Sender: TObject);
  private
    { Private declarations }
  public
    { Public declarations }
  end;

var
  Form1: TForm1;

implementation

{$R *.dfm}

procedure TForm1.FormCreate(Sender: TObject);
var
  I,J: Integer;
  aTreeNodes : TTreeNodes;
  aTreeNode : TTreeNode;
begin
  aTreeNodes := TTreeNodes.Create(TreeView1);
  for I := 1 to 10 do
  begin
    aTreeNode := TreeView1.Items.Add( TTreeNode.Create(aTreeNodes), 'DEMO' + IntToStr(I) );
    for J := 1 to random(10)+1 do
      TreeView1.Items.AddChild(aTreeNode, 'TEST' + IntToStr(J));
  end;
end;

procedure TForm1.Button1Click(Sender: TObject);
begin
  RichEdit1.Lines.LoadFromFile(
    TreeView1.Items.Item[TreeView1.Selected.AbsoluteIndex].Text + '.txt' );
end;

procedure TForm1.Button2Click(Sender: TObject);
begin
  ShowMessage( 'Counted subitems : ' +
               IntToStr(TreeView1.Selected.Count) );
end;

procedure TForm1.FormDestroy(Sender: TObject);
var
  I,J: Integer;
begin
  for I := 1 to 10 do
  begin
    for J := 0 to (TreeView1.Items[I-1].Count - 1) do
      TreeView1.Items.Item[J].Free;
    TreeView1.Items[I-1].Free;
  end;
end;

end.


procedure TForm1.Button1Click(Sender: TObject);

var
  I:      Integer;
  J:      Integer;
  K:      Integer;
  L:      Integer;
begin
  with TreeView1 do
  begin
    K := -1;
    for I := 0 to 2 do
    begin
      Inc(K);
      L := 0;
      Items.AddObject(nil, 'Item ' + IntToStr(I), nil);
      for J := 0 to I do
      begin
        Items.AddChild(Items[K], 'Item ' + IntToStr(I) + '.' + IntToStr(L));
        Inc(K);
        Inc(L);
      end;
    end;
  end;
end;

procedure TForm1.Button2Click(Sender: TObject);
var
  I:      Integer;
begin
  Memo1.Clear;
  for I := 0 to TreeView1.Items.Count-1 do
  begin
    Memo1.Lines.Add(TreeView1.Items[I].Text + ' contains ' + IntToStr(TreeView1.Items[I].Count) + ' Children');
  end;
end;

emil
pcools

The Items I need to count need to be counted when the form is created so using the TreeView1.Selected.Count stuff will not work. Also the code for opening the file would open the entire contents of a file and as stated in my original post I want to open the file but only show part of the information that it contains not the entire contents of the file.

Here is an example file (test.txt)

______________________________________

The quick brown fox jumped over the lazy dog.
Old McDonald had a farm.


Jack and Jill went up the hill.
Green eggs and ham.
Basketball is a fun sport.
_____________________________________

Now what I want to do is extract out of that text file the line that reads "Green eggs and ham." and only that  line will show in the RichEdit Control. That is what I meant when I said "specific information" in my original post.




esoftbg

Your code is way too confusing for me to work from.  Maybe if you removed that code that creates the nodes and combine the procedures into 1 which will.

1.)Count the number of Root Nodes and
2.)Count the Number of Items In a Root Node

It might help to say that the deepest level the nodes will go will be Level1 so all you will have to count for is Level0 (RootNodes) and Level1(RootNodeItems) and they have to be counted when the form is created.

here is an example of my treeview (I hope EE does not mess with the formatting)


[]
 |_[]
 |
 |_[]
 |
 |_[]
 |
[]
 |
[]
 |_[]
 |
 |_[]

So for this example the RootNode count would be 3 and the  and the RootNodeItems count would be 5 and that is all the info I need.
hello voodoo22, Here is some code that works for me to count the Nodes in each level of a TreeView, it is a button Click -


procedure TForm1.button_GetTreeNodesClick(Sender: TObject);
var
Nodes: Array of Integer;
TreeItem1: TTVItem;
i: Integer;
hItem: HTREEITEM;
GotItem: Boolean;
OutStr: String;

  function GetTItem(hTItem: HTREEITEM; Level: Cardinal): Boolean;
  var
  hItemC, hReItem: HTREEITEM;
  begin
  Result :=  False;
  if hTItem <> nil then
    begin
    TreeItem1.hItem := hTItem;
    if TreeView_GetItem(TreeView1.Handle,TreeItem1) then
      begin
      Result := True;
      if Level > Length(Nodes) then
          SetLength(Nodes, Level);
      Inc(Nodes[Level-1]);
      end;
    hItemC := TreeView_GetChild(TreeView1.Handle, hTItem);
    GetTItem(hItemC, Level+1);
    hReItem := TreeView_GetNextSibling(TreeView1.Handle, hTItem);
    if hReItem <> nil then
      GetTItem(hReItem, Level);
    end;
  end;

begin
hItem := TreeView_GetNextItem(TreeView1.Handle, hItem, TVGN_ROOT);
if hItem = nil then
  begin
  Showmessage(' No Root');
  Exit;
  end;
SetLength(Nodes, 1);
TreeItem1.mask := TVIF_CHILDREN;
TreeItem1.cChildren := 0;
GotItem := GetTItem(hItem, 1);
if GotItem then
  begin
  for i := 0 to High(Nodes) do
  OutStr := OutStr+' Level '+IntToStr(i)+' - count '+IntToStr(Nodes[i])+',';
  Label1.Caption := OutStr;
  end
end;

- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -

and I do NOT understand what you are tring to do with the text extraction from a Text file, if you already have the text you want "Green eggs and ham.", then why are you extracting it? Or if you do not have the text, then how do you know what text to extract? Can you use a Line index, like line index 5 for "Green eggs and ham."
voodo22..

If this ain't what you want, then I think I'll never get it :-))

grtz.


//CODE
function TForm1.TotalRootNodes(ATreeView: TTreeview): Integer;
var
 I,ANodes : Integer;
begin
  ANodes := 0;
  for I := 0 to ATreeView.Items.Count-1 do
     if ATreeView.Items[I].Parent = nil then
       inc(ANodes);
  Result := ANodes;
end;

function TForm1.NumberOfItems(ATreeView : TTreeView;ARootNumber: Integer) : Integer;
var
  I,ANodes,AnItem : Integer;
begin
  ANodes := 0;  AnItem := 0;
  for I := 0 to ATreeView.Items.Count - 1 do
  begin
    if ATreeView.Items[I].Parent = nil then
    begin
      Inc(ANodes);
      if ANodes = ARootNumber then
      begin
        ANodes := I;
        Break;
      end;
    end;
  end;
  for I := 0 to ATreeView.Items.Count-1 do
     if ATreeView.Items[I].HasAsParent(ATreeView.Items[ANodes]) then
       inc(AnItem);
  Result := AnItem;
end;

function TForm1.ShowLine(AFileName: AnsiString; ALine: Integer) : AnsiString;
var
  aStringList: TStringList;
begin
  aStringList := TStringList.Create;
  aStringList.LoadFromFile(ExtractFilePath(Application.ExeName) + AFileName);
  Result := aStringList[ALine-1];
  aStringList.Free;
end;

procedure TForm1.Button1Click(Sender: TObject);
var
  I: Integer;
begin

  //Counts all nodes and items
  for I := 1 to TotalRootNodes(TreeView1) do
    ShowMessage('NODE ' + IntToStr(I) + ' HAS ' + IntToStr(NumberOfItems(TreeView1,I)) + ' ITEMS');

  //Shows line 2 of your text file
  ShowMessage(ShowLine('test.txt',2));

end;
ASKER CERTIFIED SOLUTION
Avatar of pcools
pcools

Link to home
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
Start Free Trial
Hello Slick812,

When I tried to test your code delphi gives me these errors and does not compile:

[Error] Unit1.pas(79): Undeclared identifier: 'HTREEITEM'
[Error] Unit1.pas(88): Undeclared identifier: 'TTVItem'
[Error] Unit1.pas(115): Operator not applicable to this operand type
[Error] Unit1.pas(117): Missing operator or semicolon
[Error] Unit1.pas(118): Undeclared identifier: 'TreeView_GetItem'
[Error] Unit1.pas(118): Undeclared identifier: 'TreeView1'
[Warning] Unit1.pas(121): Comparing signed and unsigned types - widened both operands
[Error] Unit1.pas(125): Undeclared identifier: 'TreeView_GetChild'
[Error] Unit1.pas(125): Missing operator or semicolon
[Error] Unit1.pas(128): Missing operator or semicolon
[Error] Unit1.pas(128): Operator not applicable to this operand type
[Error] Unit1.pas(131): '.' expected but ';' found
[Error] Unit1.pas(239): Undeclared identifier: 'TreeView_GetNextItem'
[Error] Unit1.pas(239): Undeclared identifier: 'TVGN_ROOT'
[Error] Unit1.pas(240): Operator not applicable to this operand type
[Error] Unit1.pas(246): Missing operator or semicolon
[Error] Unit1.pas(247): Missing operator or semicolon
[Warning] Unit1.pas(251): For loop control variable must be simple local variable
[Error] Unit1.pas(253): Undeclared identifier: 'Label1'
[Error] Unit1.pas(79): Unsatisfied forward or external declaration: 'TForm1.GetTItem'
[Fatal Error] Project1.dpr(6): Could not compile used unit 'Unit1.pas'


I guess this kind of thing is not what the TreeView was made for so upon further thinking I am going to do my project a different (better) way and since nobody really came up with an answer that worked I am going to ask that this question be deleted. Thanks for trying though.
guessing you missed to include the unit commctrl -> just add it in your uses-clause
pcools,

Don't mind that last post I did not see your code when I made it. I did decided to use another method for all this stuff but I am going to award you the points anyway so it's not a complete waste of time.
procedure TForm1.Button1Click(Sender: TObject);
var
  I:      Integer;
  J:      Integer;
  S:      string;
const
  N = 2;
  NN = 9;
begin
  Randomize;
  TreeView1.Items.Clear;
  ListBox1.Clear;
  with TreeView1 do
  begin
    for I := 0 to N do
    begin
      S := IntToStr(I);
      ListBox1.Items.Add(S);
      Items.AddObject(nil, S + '.txt', TObject(ListBox1.Items[I]));
      Create_File(I, S + '.txt');
    end;
    for J := N+1 to NN do
    begin
      I := Random(TreeView1.Items.Count-1);
      S := IntToStr(J);
      ListBox1.Items.Add(S);
      Items.AddChildObject(Items[I], S + '.txt', TObject(ListBox1.Items[J]));
      Create_File(J, S + '.txt');
    end;
  end;
end;

procedure TForm1.Button2Click(Sender: TObject);
var
  I:      Integer;
  L:      Integer;
  M:      Integer;
begin
  M := 0;
  for I := 0 to TreeView1.Items.Count-1 do
    RecArr[I].Count := 0;
  for I := 0 to TreeView1.Items.Count-1 do
  begin
    L := TreeView1.Items[I].Level;
    if (M<L) then
      M := L;
    RecArr[L].Count := RecArr[L].Count + 1;
  end;
  Memo1.Clear;
  for I := 0 to M do
    Memo1.Lines.Add('Level ' + IntToStr(I) + '; Count = ' + IntToStr(RecArr[I].Count));
end;

emil