hrvica5
asked on
Delphi, TreeView
Hi i have one function for finding root and formshow procedure
i need much simpler Syntax
Dat.q(q)(q) is TadoDataset
function FindRootNode(ACaption: String; ATreeView: TTreeView): TTreeNode;
var LCount: Integer;
begin
result := nil;
LCount := 0;
while (LCount < ATreeView.Items.Count) and (result = nil) do
begin // and (ATreeView.Items.Item[LCou nt].Parent = nil)
if (ATreeView.Items.Item[LCou nt].Text = ACaption) then
begin
result := ATreeView.Items.Item[LCoun t];
end;
inc(LCount);
end;
end;
procedure TDomainObjectsOperatorLoca tions.Form Show(Sende r: TObject);
var i,j:Integer;
LDestNode, ObjectNode, OperatorNode, LocationNode, DeviceNode: TTreeNode;
begin
inherited;
Dat.q.Close;
Dat.q.CommandText:= ' Select * from domains';
Dat.q.Open;
TreeView1.Items.Clear;
Dat.q.First;
i:=0;
while not Dat.q.Eof do
begin // +' '+Dat.q.FieldByName('NAME' ).AsString
TreeView1.Items.Add(nil,Da t.q.FieldB yName('COD E').AsStri ng); // +' '+Dat.q.FieldByName('NAME' ).AsString
LDestNode:= FindRootNode(Dat.q.FieldBy Name('CODE ').AsStrin g, TreeView1);
Dat.qq.Close;
Dat.qq.CommandText:= 'Select objects.code, objects.name, objects.domaincode, domains.name as domainname';
Dat.qq.CommandText:= Dat.qq.CommandText + ' from objects left join domains on objects.domaincode=domains .code';
Dat.qq.CommandText:= Dat.qq.CommandText + ' where objects.domaincode='+Quote dStr(Dat.q .FieldByNa me('CODE') .AsString) ;
Dat.qq.Open;
//objects
if Dat.qq.RecordCount > 0 then
begin
TreeView1.Items.AddChild(L DestNode, 'Objects');
Dat.qq.First;
i:=0;
while not Dat.qq.eof do
begin
ObjectNode:=FindRootNode(' Objects', TreeView1); // +' '+Dat.qq.FieldByName('NAME ').AsStrin g
TreeView1.Items.AddChild(O bjectNode, Dat.qq.FieldByName('CODE') .AsString) ;
//locations
Dat.qqq.Close;
Dat.qqq.CommandText:= 'Select * from vlocations where objectCode='+QuotedStr(Dat .qq.FieldB yName('COD E').AsStri ng);
Dat.qqq.Open;
if Dat.qqq.RecordCount > 0 then
begin // +' '+Dat.qq.FieldByName('NAME ').AsStrin g
ObjectNode:= FindRootNode(Dat.qq.FieldB yName('COD E').AsStri ng, TreeView1);
TreeView1.Items.AddChild(O bjectNode, 'Locations');
j:=0;
while not Dat.qqq.eof do
begin
LocationNode:= FindRootNode('Locations', TreeView1); // +' '+Dat.qqq.FieldByName('NAM E').AsStri ng
TreeView1.Items.AddChild(L ocationNod e, Dat.qqq.FieldByName('CODE' ).AsString );
j:=j+1;
if j>3 then
Break;
Dat.qqq.Next;
end;
end;
//devices
Dat.qqq.Close;
Dat.qqq.CommandText:= 'Select * from vDevices where objectCode='+QuotedStr(Dat .qq.FieldB yName('COD E').AsStri ng);
Dat.qqq.Open;
if Dat.qqq.RecordCount > 0 then
begin // +' '+Dat.qq.FieldByName('NAME ').AsStrin g
DeviceNode:= FindRootNode(Dat.qq.FieldB yName('COD E').AsStri ng, TreeView1);
TreeView1.Items.AddChild(D eviceNode, 'Devices');
j:=0;
while not Dat.qqq.eof do
begin
LocationNode:= FindRootNode('Devices', TreeView1);
TreeView1.Items.AddChild(L ocationNod e, Dat.qqq.FieldByName('CODE' ).AsString );
j:=j+1;
if j>3 then
Break;
Dat.qqq.Next;
end;
end;
i:=i+1;
if i > 3 then
Break;
Dat.qq.Next;
end;
end;
//operators
Dat.qq.Close;
Dat.qq.CommandText:= 'Select * from vOperators where DomainCOde ='+QuotedStr(Dat.q.FieldBy Name('CODE ').AsStrin g);
Dat.qq.Open;
if Dat.qq.RecordCount > 0 then
begin
TreeView1.Items.AddChild(L DestNode, 'Operators');
Dat.qq.First;
i:=0;
while not Dat.qq.eof do
begin
OperatorNode:=FindRootNode ('Operator s', TreeView1); // +' '+Dat.qq.FieldByName('NAME ').AsStrin g
TreeView1.Items.AddChild(O peratorNod e, Dat.qq.FieldByName('CODE') .AsString) ;
i:=i+1;
if i > 3 then
Break;
Dat.qq.Next;
end;
end;
Dat.Q.Next;
end;
end;
Thx, I need simpler solution for this
i need much simpler Syntax
Dat.q(q)(q) is TadoDataset
function FindRootNode(ACaption: String; ATreeView: TTreeView): TTreeNode;
var LCount: Integer;
begin
result := nil;
LCount := 0;
while (LCount < ATreeView.Items.Count) and (result = nil) do
begin // and (ATreeView.Items.Item[LCou
if (ATreeView.Items.Item[LCou
begin
result := ATreeView.Items.Item[LCoun
end;
inc(LCount);
end;
end;
procedure TDomainObjectsOperatorLoca
var i,j:Integer;
LDestNode, ObjectNode, OperatorNode, LocationNode, DeviceNode: TTreeNode;
begin
inherited;
Dat.q.Close;
Dat.q.CommandText:= ' Select * from domains';
Dat.q.Open;
TreeView1.Items.Clear;
Dat.q.First;
i:=0;
while not Dat.q.Eof do
begin // +' '+Dat.q.FieldByName('NAME'
TreeView1.Items.Add(nil,Da
LDestNode:= FindRootNode(Dat.q.FieldBy
Dat.qq.Close;
Dat.qq.CommandText:= 'Select objects.code, objects.name, objects.domaincode, domains.name as domainname';
Dat.qq.CommandText:= Dat.qq.CommandText + ' from objects left join domains on objects.domaincode=domains
Dat.qq.CommandText:= Dat.qq.CommandText + ' where objects.domaincode='+Quote
Dat.qq.Open;
//objects
if Dat.qq.RecordCount > 0 then
begin
TreeView1.Items.AddChild(L
Dat.qq.First;
i:=0;
while not Dat.qq.eof do
begin
ObjectNode:=FindRootNode('
TreeView1.Items.AddChild(O
//locations
Dat.qqq.Close;
Dat.qqq.CommandText:= 'Select * from vlocations where objectCode='+QuotedStr(Dat
Dat.qqq.Open;
if Dat.qqq.RecordCount > 0 then
begin // +' '+Dat.qq.FieldByName('NAME
ObjectNode:= FindRootNode(Dat.qq.FieldB
TreeView1.Items.AddChild(O
j:=0;
while not Dat.qqq.eof do
begin
LocationNode:= FindRootNode('Locations', TreeView1); // +' '+Dat.qqq.FieldByName('NAM
TreeView1.Items.AddChild(L
j:=j+1;
if j>3 then
Break;
Dat.qqq.Next;
end;
end;
//devices
Dat.qqq.Close;
Dat.qqq.CommandText:= 'Select * from vDevices where objectCode='+QuotedStr(Dat
Dat.qqq.Open;
if Dat.qqq.RecordCount > 0 then
begin // +' '+Dat.qq.FieldByName('NAME
DeviceNode:= FindRootNode(Dat.qq.FieldB
TreeView1.Items.AddChild(D
j:=0;
while not Dat.qqq.eof do
begin
LocationNode:= FindRootNode('Devices', TreeView1);
TreeView1.Items.AddChild(L
j:=j+1;
if j>3 then
Break;
Dat.qqq.Next;
end;
end;
i:=i+1;
if i > 3 then
Break;
Dat.qq.Next;
end;
end;
//operators
Dat.qq.Close;
Dat.qq.CommandText:= 'Select * from vOperators where DomainCOde ='+QuotedStr(Dat.q.FieldBy
Dat.qq.Open;
if Dat.qq.RecordCount > 0 then
begin
TreeView1.Items.AddChild(L
Dat.qq.First;
i:=0;
while not Dat.qq.eof do
begin
OperatorNode:=FindRootNode
TreeView1.Items.AddChild(O
i:=i+1;
if i > 3 then
Break;
Dat.qq.Next;
end;
end;
Dat.Q.Next;
end;
end;
Thx, I need simpler solution for this
SOLUTION
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
ASKER
is your data sorted correctly ?
ASKER
I used yours, for example
exc.jpg
exc.jpg
that data isn't sorted correctly
i guess you're not using oracle ?
no point in using my sample with a stack if the data isn't sorted
i guess you're not using oracle ?
no point in using my sample with a stack if the data isn't sorted
ASKER
i'm using mssql.
i'll try to sort correctly.
thx
i'll try to sort correctly.
thx
always best to add mssql when you need a query made for that environment
i don't have an mssql at my fingertips for testing
i don't have an mssql at my fingertips for testing
ASKER
Hi i sorted,
Thank you very much you helped me like always.
but for my needs i need to make some procedure / view and sort that way my tables
Thx, Hrvica
sort.jpg
Thank you very much you helped me like always.
but for my needs i need to make some procedure / view and sort that way my tables
Thx, Hrvica
sort.jpg
ASKER CERTIFIED SOLUTION
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
ASKER
Sory I tried now with more datas and i get wrong values
I put in attach how my tabel is sorted
and jpeg how it looks in treview
thx
sort.xls
TreeView.jpg
I put in attach how my tabel is sorted
and jpeg how it looks in treview
thx
sort.xls
TreeView.jpg
No need to use parentid anymore. I modified example to use your string parentNode notation. Then oder of sql is going:
select code, node, parentNode form table order by parentNode, node;
... on creating node I allocate memory for null terminated string and this memory should be released on delete node. So add OnDeletation event to TreeView:
select code, node, parentNode form table order by parentNode, node;
procedure FindRootNode(RootNode: TTreeNode; FindIdStr: AnsiString; var node: TTreeNode);
var
i: Integer;
sNodeStr: AnsiString;
begin
if Assigned(RootNode) then
begin
sNodeStr := String(PAnsiChar(RootNode.Data));
if sNodeStr = FindIdStr then
begin
node := RootNode;
Exit;
end;
for i := 1 to RootNode.Count do
begin
sNodeStr := String(PAnsiChar(RootNode.Item[i-1].Data));
if sNodeStr = FindIdStr then
begin
node := RootNode.Item[i-1];
Break;
end
else
FindRootNode(RootNode.Item[i-1], FindIdStr, node);
if Assigned(node) then Break;
end;
end;
end;
procedure TForm1.BitBtn1Click(Sender: TObject);
var
Node, rootNode: TTreeNode;
parentId, nodeId: AnsiString;
ptr: PAnsiChar;
begin
data.First; //sort by parentid, id
TreeView1.Items.BeginUpdate;
try
TreeView1.Items.Clear;
while not data.Eof do
begin
parentId := data.FieldByName('parentNode').AsString;
nodeId := data.FieldByName('node').AsString;
rootNode := nil;
FindRootNode(TreeView1.Items.GetFirstNode, parentId, rootNode);
ptr := GetMemory(Length(nodeId)+1); //null termnated string
ZeroMemory(ptr, Length(nodeId)+1);
StrPCopy(ptr, nodeId);
if Assigned(rootNode) then
Node := TreeView1.Items.AddChildObject(rootNode, data.FieldByName('code').AsString, ptr)
else
Node := TreeView1.Items.AddObject(rootNode, data.FieldByName('code').AsString, ptr);
data.Next;
end;
finally
TreeView1.Items.EndUpdate;
end;
end;
... on creating node I allocate memory for null terminated string and this memory should be released on delete node. So add OnDeletation event to TreeView:
procedure TForm1.TreeView1Deletion(Sender: TObject; Node: TTreeNode);
var
ptr: Pointer;
begin
ptr := Node.Data;
if Assigned(ptr) then
begin
Node.Data := nil;
FreeMemory(ptr);
ptr := nil;
end;
end;
ASKER
Thank you very much for soultions but I have 2 problems
TUC is ok,
but under first node BRE, it is not OK (treeview.jpg)
2. If I have 1000 rows it slow is slow (duration.jpg)
Thank you very much and sory
duration.jpg
TreeView.jpg
TUC is ok,
but under first node BRE, it is not OK (treeview.jpg)
2. If I have 1000 rows it slow is slow (duration.jpg)
Thank you very much and sory
duration.jpg
TreeView.jpg
Ahhh. It is slow because of bad finding root node algorithm. Made some changes. Now I extract part of finding root to get top most root, then go deeper and find next root same way.
fixed finding right node too.
function GetLevelId(FindIdStr: AnsiString; iLevel: Integer): String;
var
i, j: Integer;
begin
Result := '';
j := 0;
for i:=1 to Length(FindIdStr) do
begin
if j<=iLevel then
begin
if FindIdStr[i] = '.' then
begin
Inc(j); //count points
end
else
Result := FindIdStr[i] + Result;
end
else
Break;
end;
end;
procedure FindRootNode(RootNode: TTreeNodes; FindIdStr: AnsiString; iLevel: Integer;
var node: TTreeNode);
var
i: Integer;
sNodeStr, FindIdRoot: AnsiString;
bGoDeeper: Boolean;
begin
if Assigned(RootNode) then
begin
//don't compare all nodes but use find first root logic
FindIdRoot := GetLevelId(FindIdStr, iLevel); //get pre-root id
bGoDeeper := Length(FindIdRoot) < Length(FindIdStr); //need to go deeper in tree
//find first id for root and go deeper using this line
for i := 1 to RootNode.Count do
begin
sNodeStr := String(PAnsiChar(RootNode.Item[i-1].Data));
if sNodeStr = FindIdRoot then //compare to root
begin
if bGoDeeper then
begin
FindRootNode(TTreeNodes(RootNode.Item[i-1]), FindIdStr, iLevel+1, node); //go deeper to level+1
end
else
begin
node := RootNode.Item[i-1];
Break;
end;
end;
if Assigned(node) then Break;
end;
end;
end;
procedure TForm1.BitBtn1Click(Sender: TObject);
var
Node, rootNode: TTreeNode;
parentId, nodeId: AnsiString;
ptr: PAnsiChar;
begin
data.First; //sort by parentid, id
TreeView1.Items.BeginUpdate;
try
TreeView1.Items.Clear;
while not data.Eof do
begin
parentId := data.FieldByName('parentNode').AsString;
nodeId := data.FieldByName('node').AsString;
rootNode := nil;
FindRootNode(TreeView1.Items, parentId, 0, rootNode); //always go from level 0
ptr := GetMemory(Length(nodeId)+1); //null termnated string
ZeroMemory(ptr, Length(nodeId)+1);
StrPCopy(ptr, nodeId);
if Assigned(rootNode) then
Node := TreeView1.Items.AddChildObject(rootNode, data.FieldByName('code').AsString, ptr)
else
Node := TreeView1.Items.AddObject(rootNode, data.FieldByName('code').AsString, ptr);
data.Next;
end;
finally
TreeView1.Items.EndUpdate;
end;
end;
procedure TForm1.TreeView1Deletion(Sender: TObject; Node: TTreeNode);
var
ptr: Pointer;
begin
ptr := Node.Data;
if Assigned(ptr) then
begin
Node.Data := nil;
FreeMemory(ptr);
ptr := nil;
end;
end;
fixed finding right node too.
fwiw,
the whole point of sorting and the stack is that it's not necessary to look for any parent/sub/child node
there is no point in sorting (or using a stack) when you do the lookups and move around in the tree
so if lookups are done, don't sort the data
> sorting the data slows down retreiving the query
use either the sorting+stack
or the lookups
don't use both !
the whole point of sorting and the stack is that it's not necessary to look for any parent/sub/child node
there is no point in sorting (or using a stack) when you do the lookups and move around in the tree
so if lookups are done, don't sort the data
> sorting the data slows down retreiving the query
use either the sorting+stack
or the lookups
don't use both !
ASKER
Thank you very much
if you have 1 query with the level, the parent id, the caption and optional info
it's just a straight forward running through the query and adding nodes or child nodes
this is a sample with an oracle table
Open in new window
the output looks like this, oracle database sorts this automatically
Open in new window
why not use a stack to push/pop parentnodes while you build the tree ?
i'll build a test with a tree view