Autor Beitrag
Max Payne
Hält's aus hier
Beiträge: 11

Win XP
D3.0 Prof
BeitragVerfasst: Sa 16.07.05 13:06 
Auch wenn ich die Frage hier www.delphi-forum.de/...ellenquot_45298.html schon gestellt habe eröfne ich ein neues Topic da es ja eigentlich nichts mehr mit dem alten zu tun hat (irgendwo hab ich gelesen: Neue Frage, neues Topic).

Ich möchte die verschiedenen Ebenen bei einem Treeview getrennt durchsuchen. Ich kann mit
for i := 0 to (TreeView1.Items.Count - 1do die gesamte Liste durch gehen aber da ich über 2k Einträge habe dauert das ziemlich lange und enthält Fehler. Also ist es möglich einzelne Ebenen zu durchsuchen? Wenn ja wie?

P.S.: Noch ein Topic zu TreeView :P
Gausi
ontopic starontopic starontopic starontopic starontopic starontopic starofftopic starofftopic star
Beiträge: 8548
Erhaltene Danke: 477

Windows 7, Windows 10
D7 PE, Delphi XE3 Prof, Delphi 10.3 CE
BeitragVerfasst: Sa 16.07.05 13:12 
Soviel ich weiss, bekommt man mit GetNextSibling den nächsten Knoten auf derselben Ebene. Kindknoten des aktuellen Knotens werden dadurch übersprungen.

btw: Mit dem VirtualTreeView dürften Geschwindigkeitsprobleme nicht mehr auftreten. Bin gerade dabei, mich da einzuarbeiten, und da kann man 40.000 Knoten in Nullkommanix untersuchen...

_________________
We are, we were and will not be.
Max Payne Threadstarter
Hält's aus hier
Beiträge: 11

Win XP
D3.0 Prof
BeitragVerfasst: Sa 16.07.05 13:16 
danke ich werds probieren. Naja das mit der Geschwindigkeit... Bisher hab ich versucht das andres hinzubekommen jedoch brauchee ich dazu in der schleife nochmal 3 Schleifen die nochmal durchsuchen... Nicht sehr gut gelöst aber ich war ja nur am probieren :wink:
Klabautermann
ontopic starontopic starontopic starontopic starontopic starhalf ontopic starofftopic starofftopic star
Veteran
Beiträge: 6366
Erhaltene Danke: 60

Windows 7, Ubuntu
Delphi 7 Prof.
BeitragVerfasst: Sa 16.07.05 15:36 
Hallo,

zuersteinmal, du kannst über die Eigenschaft Level abfragen auf welcher Ebene sich der aktuell berachtete Knoten befindet. tTreeItems bietet dir mit GetFirstNode eine Möglichkeit den ersten Knoten des Baumes zu suchen. Bei tTreeItem kannst du mit GetFirstChild und GetNextChild sowie mit GetNext und natürlich den genannten GetNextSibling navigieren. Mit einer Kombiation dieser Funktionen kannst du sicherlich viel Geziehlter suchen als mit deinen Schleifen. Zum einen kannst du deine suche Reursiv gestalten, was sich bei Bäumen immer anbietet, auch kannst du, wenn du in einer Sackgasse belandet bist kannst du die suche an der Stelle einfacher abbrechen.

Folgende Funktion ist nicht getestet (da ich keine lust habe mit einen Beispielbaum auf zu bauen) aber ich hoffe sie Funktiniert und ist schneller als deine variante, sehe es ansonsten als Konzeptstudie ;):
ausblenden Delphi-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
16:
17:
18:
19:
function FindNodeOnLevel(aParentNode: tTreeNode; aCaption: String;
  aLevel: Integer): tTreeNode;
  var
    ActNode : tTreeNode;
begin
  Result := nil// mit nichts gefunden vorinitialisieren
  if (aParentNode <> niland (aParentNode.HasChildren) and
     (aParentNode.Level < aLevel) then begin
    ActNode := aParentNode.getFirstChild; // Mit ersten Kind initialisieren
    while (ActNode <> niland (Result = nildo begin
      if (ActNode.Level < aLevel) and (ActNode.HasChildren) then // noch nciht das richtige Level
        Result := FindNodeOnLevel(ActNode, aCaption, aLevel)
      else if (ActNode.Level = aLevel) and
              (AnsilowerCase(ActNode.Text) = AnsiLowerCase(aCaption)) then // Das ist der gesuchte Knoten
        Result := ActNode;
      ActNode := aParentNode.GetNextChild(ActNode); // Neuen Knoten für neuen Schleifendurchlauf
    end// mit allen kindknoten wenn noch nichts gefunden wurde
  end// Wir haben eine Parent welches Kinder hat und sind noch nicht zu tief im baum
end// FindNode On Level


Wie du (wenn du dich ein wenig reingedacht erkennst) sucht diese Rekursiv nach einen Knoten mit einer bestimmten Bezeichnung (G&K Schreibung egal) auf einer Bestimmten ebene (Hauptknoten haben Level 0). Hierbei werden Knoten die auf einem Level welches größer ins als das gesuchte nciht beachtet und sobalt der Knoten gefunden wurde wird auch nicht mehr weiter gesucht. Wird der Knoten nicht gefunden (nicht existent) liefert die Funktion NIL zurück.

Ein Aufruf könnte so aussehen:

ausblenden Delphi-Quelltext
1:
2:
3:
4:
5:
6:
procedure TForm1.Button1Click(Sender: TObject);
  var
    SearchNode : tTreeNode;
begin
  SearchNode := FindNodeOnLevel(TreeView1.Items.GetFirstNode, 'Gesucher Text'4);
end;


Noch ein kleiner hinweis zur Geschwindigkeit. Wenn du etwas an den Items änders (z.B. auch beim Baum aufbauen) kannst du das erheblich beschleunigen, wenn du vorher TreeView1.Items.BeginUpdate; aufrufen und hinterher TreeView1.Items.EndUpdate; aufrufen, das verhindert, dass nach jeder änderung der Baum neu gezeichnet wird. Aus sicherheitsgründen sollte das in einer Try Finally konstruktion geschehen, damit der Baum bei einem Fehler nicht tot bleibt.

ausblenden Delphi-Quelltext
1:
2:
3:
4:
5:
6:
TreeView1.Items.BeginUpdate;
try
  {Hier die Baummanipulationen durchführen}
finally
  TreeView1.Items.EndUpdate;
end;


So, ich hoffe das bringt dich weiter.

Klabautermann
Max Payne Threadstarter
Hält's aus hier
Beiträge: 11

Win XP
D3.0 Prof
BeitragVerfasst: Sa 16.07.05 17:17 
Auch wenn ich noch nicht ganz dahinter gestiegen bin (mein Kopf dröhnt durch den Mist den ich selbst verzapft hab) sieht es nicht schlecht aus. probieren werd ich das heute nicht mehr denke ich.

Bei meinem aktuellem versuch klappt es (fast :( ). Falls Interesse besteht kann ich Posten was ich mir Gedacht hab.

Naja wie gesagt erstmal den Kopf frei bekommen und weiter...
Max Payne Threadstarter
Hält's aus hier
Beiträge: 11

Win XP
D3.0 Prof
BeitragVerfasst: Di 19.07.05 09:36 
Ok klappt soweit alles. Danke.

Allerdings musste ich die Funktion etwas anpassen um auch in der ersten ebene suchen zu können ;)

Am ende schauts so aus:
ausblenden Delphi-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
16:
 MyNode1 := ProvinzenTree.Items.AddChild(nil, Provinzen[1].Kontinent);
 for i := 1 to 2600 do
 begin
  MyNode1 := FindNodeOnLevel(nil, Provinzen[i].Kontinent, 0);
  if MyNode1 = nil then
   MyNode1 := ProvinzenTree.Items.AddChild(nil, Provinzen[i].Kontinent);
  MyNode2 := FindNodeOnLevel(MyNode1, Provinzen[i].Region, 1);
  if MyNode2 = nil then
   MyNode2 := ProvinzenTree.Items.AddChild(MyNode1, Provinzen[i].Region);
  MyNode3 := FindNodeOnLevel(MyNode2, Provinzen[i].Gebiet, 2);
  if MyNode3 = nil then
   MyNode3 := ProvinzenTree.Items.AddChild(MyNode2, Provinzen[i].Gebiet);
  MyNode4 := FindNodeOnLevel(MyNode3, Provinzen[i].Name, 3);
  if MyNode4 = nil then
   MyNode4 := ProvinzenTree.Items.AddChild(MyNode3, Provinzen[i].Name);
 end;