Board index » delphi » Give me TTreeView or give me death.

Give me TTreeView or give me death.

Hi all.

I installed Delphi 3.0 on my NT 4.0 workstation last Thursday for the
first time.  While I've never looked at a line of Pascal, I've worked
in C, FoxPro & VB before - so I have a little programming experience.
But just a little. ;)

Everything went great for two days.  I learned how to use the IDE and
the various components.  Looked at examples and help files.  And
started my first application, which is rather basic I think.  The part
I'm currently totally confused on is this:  I have about 100 or so
locations.  Each location has a Name, a category, a subsection,  an X,
a Y and a Z string.  An example in a text file would be:

category=My Home
subsection=The Kitchen
X=127
Y=55763
Z=0

I've wanted a TreeView of all the items in the file with nodes for
category and subections.  So, in the case above, the root would be My
Home with a node off of it name The Kitchen.  I want to  be able to
select one of the items on the tree and click a button and the X,Y,Z
coords would be displayed.  I'm totally confused on how/where to store
the XYZ information.

I've spent *a lot* of time reading tutorials and introductions and
looking at other people's code.  I've gotten the TreeView to work with
AddChild/AddFirst, but that's about it - I still can't read files or
figure out where to store XYZ.  I'm feeling no closer to an answer so
ANY help with this would be warmly welcomed.

David

 

Re:Give me TTreeView or give me death.


In article <37cca1c8.84970...@news.visi.com>, preacher@<ZeroSpam>happycouch.org

Quote
(David Saraniero) writes:
>I've spent *a lot* of time reading tutorials and introductions and
>looking at other people's code.  I've gotten the TreeView to work with
>AddChild/AddFirst, but that's about it - I still can't read files or
>figure out where to store XYZ.  I'm feeling no closer to an answer so
>ANY help with this would be warmly welcomed.

Use a record to hold the string values and put a pointer to the record in the
Data property of the treenode :-

OTTOMH - not tested

type
  PPositions = ^TPositions;
  TPositions = record
     X : string;
     Y : string;
     Z : string;
   end;
var
  TN : TTreeNode;
  PtrPositions : PPositions;
begin
  TN := TreeView1.Items.Add(nil, 'MyHome');
  while not EOF do
    GetMem(PtrPositions, SizeOf(TPositions));
    {get SubSectionf, Xf, Yf, Zf from file}
    with PtrPositions^ do begin
      X := Xf;
      Y := Yf;
      Z := Zf;
    end;
   TreeView1.AddObject(TN, SubSection, PtrPositions);
   {move to next item in file}
 end;
end;

procedure TForm1.TreeView1MouseDown((Sender, Button, Shift, X, Y)  
var
  TN : TTreeNode;
begin
  TN := GetNodeAt (X, Y);
  if TN <> nil
   if TN.Data <> nil then
     with PPositions(TN.Data)^ do
       ShowMessage(Format('X : %s'#13'Y : %s'#13'Z : %s', [X, Y, Z]);
end;

and free the memory used for the positions in the Form OnClose event handler :-

var
  TN : TTreeNode;
begin
  TN := TreeView1.Items.GetFirstNode;
  while TN.Data = nil do  // first node has no pointer to TPositions
    TN := TN.GetNext;
  while TN <> nil do begin
    FreeMem(PPositions(TN.Data));
    TN := TN.GetNext;
  end;
end;

Alan Lloyd
alangll...@aol.com

Re:Give me TTreeView or give me death.


On 30 Aug 1999 21:18:50 GMT, alangll...@aol.com (AlanGLLoyd) wrote:

Quote
>Use a record to hold the string values and put a pointer to the record in the
>Data property of the treenode :-

Thank you, Alan, for the source code.  It helped *a lot*, but I still
have a few questions, if I may.

Quote
>and free the memory used for the positions in the Form OnClose event handler :-

If I never close the form until I close the actual application, do I
need to worry about freeing the memory?  I'm a bit sketchy on the
GetMem/FreeMem concept.  If closing the form closes the app, can I
leave this part out?  

I'm just trrying to get a feel for how all this works... so would the
code below function correctly?  The pointers, I believe, are what's
confusing me.  But if I simply wanted to hardcode a small list with
the XYZ string replacing the X & Y & Z strings would this be valid?

type
  PPositions = ^TPositions;
  TPositions = record
   XYZ : string;
end;

var
  TN : TTreeNode;
  PtrPositions : PPositions;
  TheCoords : String;
  TravelNode : TTreeNode;

begin
   TreeView1.Items.AddFirst(nil, 'City');
   TravelNode :=  TreeView1.Items.AddChild( TreeView1.Items[0],
'Home');
     GetMem(PtrPositions, SizeOf(TPositions));
     PtrPositions^.XYZ := '2499 922 0';
end;

Thank you for all your help so far.
David

Re:Give me TTreeView or give me death.


ZeroSpam happycouch.org (David Saraniero) heeft geschreven in bericht
<37cca1c8.84970...@news.visi.com>.

[snip]

 I'm totally confused on how/where to store

Quote
>the XYZ information.

Well, you've choosen one of the most complicated components...
Ttreeview contains a list of TTreenode's. ( MyView.Items[..] ). Each
TTreenode has a field called Data, which is nothing more then a generic
pointer. Generic pointers can point to TAnything, meaning you have to do the
footwork yourself. You can group the XYZ-stuff into a record, as in:

type
TMyStuff = record
   X : integer;
   Y : Double;
   Z : char;
end;
PTMyStuff =  ^TMyStuff;
...
Then, each time a new node is created, you can have the pointer in it's
datafield point to a TMyStuff record:

var
  NewNode : TTreeNode;
  MyStuff : PTMyStuff;

NewNode := TTreeNode.Create; // create the node;
New( MyStuff);   // allocate some heap space;
With MyStuff^ do
begin
  X := ...;
  Y := ...;
  Z := ...;
end;

NewNode.Data := MyStuff;
(NewNode.Data^ now points to the datarecord, located somewhere on the heap)

Then, to access the data later on, you need to typecast the pointer:

AnInteger := TMyStuff(MyTreeView.Items[i]^).X;

note that :
- Delphi will free the TTreeView on exit, but _you_ need to free the heap
space each pointer points to.
- The code above is unchecked, and I've just returned from holiday.  You've
been warned....

Regards and good luck,
Dirk Claessens

<Dirk DOT Claessens AT Village DOT uunet DOT be>
Sorry, mailheader is forged...

Re:Give me TTreeView or give me death.


Hi Dirk,

Would be so kind as to post a small example of how to do the clean up?  This
is the part that's been confusing me.

Say on the CloseQuery event of the Treeview's form, how would you clean up
all the Data items associated with the Treenodes in the Treeview.

Thanks in advance,
Brian Simmons
bsimm...@centrasoft.com
http://www.centrasoft.com

Quote
Dirk Claessens <will.bou...@back.com> wrote in message

news:7qhb1i$r9u$1@nickel.uunet.be...
Quote

> ZeroSpam happycouch.org (David Saraniero) heeft geschreven in bericht
> <37cca1c8.84970...@news.visi.com>.

> [snip]

>  I'm totally confused on how/where to store
> >the XYZ information.

> Well, you've choosen one of the most complicated components...
> Ttreeview contains a list of TTreenode's. ( MyView.Items[..] ). Each
> TTreenode has a field called Data, which is nothing more then a generic
> pointer. Generic pointers can point to TAnything, meaning you have to do
the
> footwork yourself. You can group the XYZ-stuff into a record, as in:

> type
> TMyStuff = record
>    X : integer;
>    Y : Double;
>    Z : char;
> end;
> PTMyStuff =  ^TMyStuff;
> ...
> Then, each time a new node is created, you can have the pointer in it's
> datafield point to a TMyStuff record:

> var
>   NewNode : TTreeNode;
>   MyStuff : PTMyStuff;

> NewNode := TTreeNode.Create; // create the node;
> New( MyStuff);   // allocate some heap space;
> With MyStuff^ do
> begin
>   X := ...;
>   Y := ...;
>   Z := ...;
> end;

> NewNode.Data := MyStuff;
> (NewNode.Data^ now points to the datarecord, located somewhere on the
heap)

> Then, to access the data later on, you need to typecast the pointer:

> AnInteger := TMyStuff(MyTreeView.Items[i]^).X;

> note that :
> - Delphi will free the TTreeView on exit, but _you_ need to free the heap
> space each pointer points to.
> - The code above is unchecked, and I've just returned from holiday.
You've
> been warned....

> Regards and good luck,
> Dirk Claessens

> <Dirk DOT Claessens AT Village DOT uunet DOT be>
> Sorry, mailheader is forged...

Re:Give me TTreeView or give me death.


You would walk down the tree from 0 to Count-1 and for each Data pointer
that isn't nil, free the memory.

Woody

Quote

> Would be so kind as to post a small example of how to do the clean up?
This
> is the part that's been confusing me.

Re:Give me TTreeView or give me death.


In article <37cbe9db.3555...@news.visi.com>, preacher@<ZeroSpam>happycouch.org

Quote
(David Saraniero) writes:
>>and free the memory used for the positions in the Form OnClose event handler
>:-

>If I never close the form until I close the actual application, do I
>need to worry about freeing the memory?  I'm a bit sketchy on the
>GetMem/FreeMem concept.  If closing the form closes the app, can I
>leave this part out?  

No - every GetMem should have a FreeMem counterpart (or similar pairs of code
for obtaining and freeing memory). Similarly when you start creating objects
yourself (instead of Delphi doing it for you in the IDE), any objects you
create which do not have an Owner must be Free'd. Any memory allocated by your
program and not freed will become "lost" to the operating system (this is known
as a memory or resource leak).

Quote

>I'm just trrying to get a feel for how all this works... so would the
>code below function correctly?  The pointers, I believe, are what's
>confusing me.  But if I simply wanted to hardcode a small list with
>the XYZ string replacing the X & Y & Z strings would this be valid?

>type
>  PPositions = ^TPositions;
>  TPositions = record
>   XYZ : string;
>end;

>var
>  TN : TTreeNode;
>  PtrPositions : PPositions;
>  TheCoords : String;
>  TravelNode : TTreeNode;

>begin
>   TreeView1.Items.AddFirst(nil, 'City');
>   TravelNode :=  TreeView1.Items.AddChild( TreeView1.Items[0],
>'Home');
>     GetMem(PtrPositions, SizeOf(TPositions));
>     PtrPositions^.XYZ := '2499 922 0';
>end;

A pointer is just a reference for your code saying "this is the address of the
item you want". At base level of computer code every item is accessed by a
pointer, at a higher level such references are replaced by a variable name
(easier for humans to use and remember) which the program language replaces
automagically with the pointer (the process of interchanging variable names and
pointers is known as "referencing" and de-referencing"). Delphi does nearly all
referencing and de-referencing for you, except for record types. For these you
specify the type of the record, and the type of a pointer to that record, and
then use GetMem to return a pointer to memory for the record. That returned
pointer is used directly _as_ a pointer, or suffixed with a caret (^ ==
shift-6) to mean "the contents of the memory pointed to".

The your above code would not work because while you've allocated and filled
the memory, you have not stored the pointer to the memory so that you can
recall the data you have stored. Either add code of TravelNode.Data :=
PtrPositions, or get the memory and store the string before adding the naode
and then use TreeView1.Items.AddObject() to add a node with the pointer to the
string.

You need to have a feel for the concept of pointers and memory and meory
contents in order to understand what is happening in your code.

OTOH if you're just storing a single string for each treenode, you could use a
TStringList to store the strings and keep the index to each string in the
treeview Data property. If you want a bit of code to do this, e-mail me and
I'll send you an example direct.

Alan Lloyd
alangll...@aol.com

Other Threads