Visit our Sponsor   Visit our Sponsor
delphi3000.com - the free delphi knowledge platform
delphi3000.com - the free delphi knowledge platform
Have a look at your member-status

connecting people's knowledge


  - Recent ArticlesRSS feed for Recent Articles on delphi3000.com
  - List of All Articles
  - Top Viewed Articles
  - Articles (+Attachem.)
  - Articles Of Interest
  - Categories
  - Top Uploader
  - Search
  - Index

  - My Home
  - Submit an Article
  - My Articles
  - My Personal Data
  - My Bookmarks
  - Activities
  - Login/Logout

  - Sign Up
  - Why Sign Up
  - Newsletter

  - Press
  - Advertise

  - Contact
  - Feedback





Community
Borland
ClubeDelphi
Dr. Bob
UK-BUG
Delphi Meetings
Planeta Delphi







Startblatt.de






Share this article with friendsShare this article with friends
Rate this articleRate this article - to keep the quality of delphi3000.com !
Comment this article or read through previous comments (7)


Build a Table Tree from Records to ObjectsGo to Max Kleiner's websiteComponent available for this articleFormat this article printer-friendly!Bookmark function is only available for registered users!
How to show a database self join in a TreeView
Product:
Delphi all versions
Category:
Object Pascal
Skill Level:
Scoring:
Last Update:
08/20/2007
Search Keys:
delphi delphi3000 article borland vcl code-snippet recursion composite-pattern self-join treeview
Times Scored:
5
Visits:
11259
Uploader: Max Kleiner
Company: kleiner kommunikation
Reference: N/A
Component Download: http://max.kleiner.com/download/recview.zip
 
Question/Problem/Abstract:
In a relational database like the well known IBLocal you find a table DEPARTMENT which has a self join on her own, means there is a tree inside with a Parent/Child structure.
Answer:



In a relational database like the well known IBLocal you find a table DEPARTMENT which has a  self join on her own, means there is a tree inside with a Parent/Child structure:

DEPT_NO       DEPARTMENT                 HEAD_DEPT
100           Sales and Marketing        000
120           European Headquarters      100
121           Field Office Swiss         120
and so on...

This article is aimed mainly at people interested in trees and recurcions who need to find their  way around self referencing system and get going with a object-visualisation in a tree. Furthermore it's an example for the Composite Design Pattern.
These recursive relationships are often many levels deep, and the deeper the nesting becomes the more difficult it is for end-users to manage them with normal grid. Solving this problem demands a tool capable of editing hierarchically-related data.  
First we need a startprocedure mainly to call the query, build the tree with records in objects and   show the tree at last:

procedure TForm1.btnTreeSelfClick(Sender: TObject);
var
  dimlist: TStringList;
begin
  dimlist:= TStringlist.create;
  datdepartment:= TBusinessObj.Create(NIL);
  try
    if datDepartment.open_recursiveQuery then
    with TDims.create(NIL, DimList) do begin
      FillTree(treeview1, NIL);
      Free;
    end;
    treeview1.FullExpand;
    btnLTree.visible:=true;
  finally;
    dimlist.Free;
    datDepartment.Free;
  end;
end;

The records in the query must follow one condition [child# > parent#], means a child like  "FieldOffice Swiss" has a child# 121 so the parent it belongs is 120. So we call the query and open the dataset:    


function TBusinessObj.open_recursiveQuery: boolean;
begin
  result:= false;
  with qryselfTree do begin
    try
      SQL.Clear;
      SQL.add('SELECT dept_no, department, location, head_dept' +
              ' FROM department ORDER BY dept_no');
      open;
      result:= true;
    except on EDataBaseError
          do showmessage('data not found');
    end;
  end;
end;


Next we implement a class which holds at runtime the whole tree table in objects. Every object is a stored record from the table DEPARTMENT with the attributes you want to publish or  manipulate at runtime. Grace the members FParent, FChild the whole table is chained in objects  with a top level object, in our case the CORPORATE HEADQUARTERS. This top level object doesn't have a parent, the parent is NIL.


TDims = class(TObject)
private
    FstrDimArt: string ;
    FstrDimArtBez: String ;
    FParent: TDims ;
    FChilds: TList ;
  public
    Constructor create(Sender: TDims; myRegister: TStringList);
    Destructor Destroy; override;
    Procedure FillTree(aOl: TTreeview; xnode: TTreenode);
    Function IsDimartInChilds (DimArt: string): Boolean;
    property DimArtBez: string Read FstrDimArtBez;
    property DimArt: string Read FstrDimArt;
    property treechilds: TList read FChilds;
  end ;


Now comes the real power part, a recursive constructor which collects all records to build the  tree in memory. When a parent like "Sales and Marketing" finds some childs like "European  Headquarters" it creates new objects in a recursion and adds the object to the list:

        FChilds.Add(TDims.create(self, myRegister));

Recursions aren't dark chapter by opening in Delphi the debug windows "Call Stack and Local  Variables" you'll learn a lot. When a function name appears anywhere else in a statement block,  the compiler interprets it as a recursive call to the function itself.
The constructor has been used to recursively include another objects. But in every tree an object  without childs terminates without having cycles in them. The last level of a tree is almost the  deepness of recursions.
By the way do you know the explanation of a recursion in a "well behaved" dictionary:

Recursion: See under Recursion ;)

Let jokes aside, here it is:
A programming technique in which a subroutine calls itself. Use care to ensure that a recursion eventually exits. Otherwise, an infinite recursion will cause a stack fault.

  
constructor TDims.create(Sender: TDims; myRegister: TStringList);
var
  bmAkt: TBookmark;
Begin
  inherited Create;
   with datDepartment.qrySelfTree do begin
    FstrDimArt:= fieldByName('DEPT_NO').AsString;
    FstrDimArtBez:= fieldbyName('DEPARTMENT').AsString;
    myRegister.AddObject(Format('%10s',[FstrDimArt]), self);
    FChilds:= TList.Create;
    FParent:= Sender;
    bmAkt:= GetBookmark;
    if Locate('DEPT_NO', FstrDimArt,[]) then
    while Not (EOF) Do Begin
      if (fieldByName('HEAD_DEPT').Asstring = FstrDimArt) then
        FChilds.Add(TDims.create(self, myRegister));
      Next;
    end;
    GotoBookmark (bmAkt);
    FreeBookmark (bmAkt);
  end;
end;


Destructor TDims.Destroy;
var  i: integer;
Begin
  if FChilds <> NIL Then
    For i := 0 to FChilds.Count -1 do
      TDims(FChilds[i]).Free;
    FChilds.Free;
  Inherited Destroy;
end;

Now comes the last part, the most efficient way to represent the tabel tree in a view. TTreeView represents a window that displays a hierarchical list of items, such as the headings in a document, the entries in an index, or the files and directories on a disk.
Use TTreeView to add an expanding and contracting outline to a form. Each node in a tree view  control consists of a label and a number of optional bitmapped images. Each node can have a  list of subnodes associated with it. By clicking on a node, the user can expand or collapse the associated list of subnodes.
At run-time nodes can be added and inserted by using the TTreeNodes methods AddChildFirst, AddChild, AddChildObjectFirst, AddChildObject, AddFirst, Add, AddObjectFirst, AddObject and Insert. We only need AddChild:


Procedure TDims.FillTree(aOl: TTreeview; xnode: TTreenode);
var
i: integer ;
dbcontent: string[255];
begin
  dbcontent:= dimart +' '+ dimartbez;
  xnode:= aOl.items.addchild(xnode, dbcontent);
  for i:= 0 to treechilds.Count -1 do
     TDims(treechilds.items[i]).FillTree(aOl, xnode);
end;

I wish more X-mas trees like treeviews ;)





Please rate this article!
Skill level:
BeginnerExpert

Useful:
No!Very!

Overall rating:
PoorExcellent



Comments to this article
Write a new comment
Download Example
    Anderson Cristian Silva (Aug 28 2003 5:14PM)

I am wanting an example about to download where I can go down.
Respond

RE: Download Example
max kleiner (Aug 29 2003 11:38AM)

more of that in my new book "Patterns konkret", for the meantime:
http://max.kleiner.com/download/recview.zip
Respond

DB-Tree-List
    SR (Dec 29 2002 9:29PM)

Interesting article, there is a component which handles data-sensitive trees (QuantumDBTreeList). See under "www.devexpress.com".
Respond

RE: DB-Tree-List
Max Kleiner (Jan 7 2003 5:16PM)

In short, if you have a need to represent and manipulate (drag'n drop, creating nodes etc.) self-referenced data structures within your application, there is no substitute for the ExpressDBTreeView ;).

Respond

RE: RE: DB-Tree-List
wp_yun (Jan 10 2003 6:04AM)

aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
Respond

RE: RE: RE: DB-Tree-List
Max Kleiner (Jan 13 2003 11:40AM)

is this a triple A or a multiple a ;)
Respond

RE: RE: RE: RE: DB-Tree-List
wangcw wangcw (Jan 22 2008 4:10PM)

2225555555555555555555555
Respond














 
Sign up to consume product discounts for Bronze memberships !

read more


  Visit our Sponsor

 

  Community Ad of
E. Irigoyen
 
   














 







     
  Copyright © 2000 - 2007 delphi3000.com - All rights reserved. Terms of use. || Privacy
delphi3000.com is a service by bluestep.com IT-Services GmbH (Vienna)