Einzelnen Beitrag anzeigen

Satty67

Registriert seit: 24. Feb 2007
Ort: Baden
1.566 Beiträge
 
Delphi 2007 Professional
 
#5

Re: TreeView-Nodes anhand Pfad-String finden (zu langsam)

  Alt 5. Mär 2009, 17:22
So, also ich bin auf eine Hürde gestossen:

Die Nodes kennen Ihre Sub-Nodes nicht. Keine Itemlisten wie z.B. beim MenuItem. Nur die globae Itemliste und eben Parent/HasChildren als einzige Zuordnung.

Ich kann also den passenden LvL-0 Node ermitteln, aber danach die Schleife nicht auf die Sub-Nodes beschränken. Den Vergleich natürlich schon, indem ich auf Parent prüfe. Dadurch durchlaufe ich aber die ItemListe gleich mehrmals komplett (je nach LvL-Tiefe).

Kann sein, das ich einen Denkfehler drin hab', dann bitte nochmal in die richtige Richtung schupsen

***

Dein Ansatz war aber natürlich trotzdem ein richtiger Weg, nur hab' ich jetzt das Pferd von hinten aufgezäumt. Ich ermittel vom Schleifendurchlauf den LvL des gesuchten Nodes, indem ich die \ im Pfad zähle. Erst wenn der LvL passt, dann vergleiche ich jeweils den kompletten Pfad miteinander.

Könnte ich es wie oben beschrieben machen, würde sich bei jedem Fund die Datenmenge im Mittel halbieren, so ist es leider nicht ganz so effektiv. Das hat aber immerhin etwa 30% mehr Geschwindigkeit gebracht:
Delphi-Quellcode:
function FindNodeByPath(const aTreeView: TTreeView; aPath: String): TTreeNode;
var
  i, lvl : Integer;
  NodeText : String;
begin
  Result := NIL;
  if Assigned(aTreeView) and (Length(aPath)>0) then begin

    // Pfadstring UpperCase
    aPath := AnsiUpperCase(aPath);

    // Delimiter anfügen
    if aPath[Length(aPath)] <> '\then aPath := aPath +'\';

    // Zählen welcher Level der Node haben müsste
    lvl := -1;
    for i := 1 to Length(aPath) do
      if aPath[i]='\then inc(lvl);

    // Alle Items aus dem TreeView testen
    for i := 0 to aTreeView.Items.Count-1 do begin

      // Vorbedingungen testen
      if (aTreeView.Items[i].Level = lvl) then begin
        // Jetzt evtl. passenden Node-Pfad mit Gesuchtem vergleichen
        if AnsiUpperCase(GetNodePath(aTreeView.Items[i], True)) = aPath then begin
          Result := aTreeView.Items[i];
          Break;
        end;
      end;

    end;
  end;
end;
"GetNodePath" in die Schleife zu bauen (statt Funktionsaufruf) bringt übrigens keine 100ms. Auch nicht schneller, vorher neben LvL noch Node.Text zu vergleichen (das hatte ich auch schon mit drin).

Im ganzen werden übrigens 24.000 Nodes angelegt. Die erste Methode benötigte dazu noch >30.000ms. Die etwas optimierte nur noch 20.000ms. Die ganz andere Methode mit der String/Object-Liste und IndexOf ist allerdings immer noch um Längen schneller (<3.000ms).

Vielleicht hab' ich ja oben einen Denkfehler gemacht, indem ich himitsu's Vorschlag verworfen hab'. Aber sieht so aus, als ob die spezielle Datenstruktur des TreeView nicht mehr hergibt?

€: Gerade kommt mir etwas in den Sinn. Kommt der Eintrag "Kat\SubKat" immer nach dem Eintrag "Kat" in der ItemListe? Also ganz egal wie oft zuvor Nodes zugefügt und gelöscht worden sind? Wenn ja, müsste ich mir himitsu's Vorschlag nochmal vornehmen
  Mit Zitat antworten Zitat