AGB  ·  Datenschutz  ·  Impressum  







Anmelden
Nützliche Links
Registrieren
Zurück Delphi-PRAXiS Code-Bibliothek Neuen Beitrag zur Code-Library hinzufügen Delphi TreeViewTools (rund um Node.Text und Node-Path)
Thema durchsuchen
Ansicht
Themen-Optionen

TreeViewTools (rund um Node.Text und Node-Path)

Ein Thema von Satty67 · begonnen am 8. Mär 2009 · letzter Beitrag vom 8. Mär 2009
Antwort Antwort
Satty67

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

TreeViewTools (rund um Node.Text und Node-Path)

  Alt 8. Mär 2009, 10:45
Unter D5 ist VirtualTreeView nicht verfügbar, weshalb ich mich mit TTreeView begnügen musste. Dabei sind ein paar kleine Funktionen entstanden, die beim Anlegen und Verwalten der Nodes helfen (speziell Node.Text). Eine besonders zeitkritische Funktion wurde hier im Forum in diesem Thread optimiert.

Die Procedure/Functionsnamen sind im Prinzip selbsterklären, hier ein kleine Zusammenfassung:

function GetNodePath(aNode:TTreeNode; WithTailingDelimiter: Boolean): String;
Ermittelt für einen Node den Pfad-String, der übergeordnete Node-Namen und den eigenen enthält.

procedure NodesToPathList(aTreeView: TTreeView; aStringList: TStrings; WithTailingDelimiter: Boolean; DataTyp : TNodesToPathListTyp = ntpl_DataAll);
Dehnt die obige Funktion auf den ganzen TreeView aus. aStringlist enhält danach die Pfade und zugehörige Nodes als Objekt. Kann als Speicherliste, Referenzliste oder Auswahlhilfe verwendet werden. Durch filtern von Data kann z.B. auch nur eine Ordnerliste oder Datenliste gebildet werden.

function FindNodebyPath(aTreeView: TTreeView; aPath: AnsiString): TTreeNode;
Findet einen Node, nur durch Angabe des Pfades (wie er durch eine der obigen Funktionen erstellt wurde). Details zum Code findet man im o.a. Link, die Kernfunktion wurde von himitsu geschrieben.

function NodeTextExistsInTwig(aTreeView: TTreeView; aParentNode: TTreeNode; aText : String): Boolean;
Prüft, ob ein Bezeichner in einem TreeView-Zweig bereits existiert (case insensitive)

function GetUniqueNodeText(aTreeView: TTreeView; aParentNode: TTreeNode; aNodeText : String; OnlyInTwig : Boolean = True): String;
Erweiterung der letzten Funktion, mit der man sich gleich einen eindeutigen Namen zurückgeben lassen kann. Dabei kann die Eindeutigkeit auf einen Zweig oder den ganzen TreeView eingestellt werden.

Delphi-Quellcode:
unit TreeViewTools;

interface

uses SysUtils, ComCtrls, Classes;

type
  TNodesToPathListTyp = (ntpl_DataNil, ntpl_DataAssigned, ntpl_DataAll);
  TArrayOfString = array of String;

{<--- Funktion, die aus einem Node (mit Parents) ein PathStr bildet --->}
function GetNodePath(aNode:TTreeNode; WithTailingDelimiter: Boolean): String;
{<--- Trägt kompletten Pfad der Parent-Nodes eines TreeView in eine StringList --->}
procedure NodesToPathList(aTreeView: TTreeView; aStringList: TStrings; WithTailingDelimiter: Boolean;
                         DataTyp : TNodesToPathListTyp = ntpl_DataAll);
{<--- Findet einen Node durch Angabe des Pfadnamen --->}
function FindNodebyPath(aTreeView: TTreeView; aPath: AnsiString): TTreeNode;
{<--- Prüft, ob in einem TreeZweig ein Node.Text bereits exitiert --->}
function NodeTextExistsInTwig(aTreeView: TTreeView; aParentNode: TTreeNode; aText : String): Boolean;
{<--- Gibt ein unique NodeText zurück, entweder für Zweig oder ganzen Baum --->}
function GetUniqueNodeText(aTreeView: TTreeView; aParentNode: TTreeNode;
                           aNodeText : String; OnlyInTwig : Boolean = True): String;

implementation

(***************************************************************************
  Funktion, die aus einem Node (mit Parents) ein PathStr bildet
  Achtung! aNode-Pointer wird innerhalb verändert
***************************************************************************)

// himitsu: umgeschrieben, weniger .Parent und übersichtlicher
function GetNodePath(aNode:TTreeNode; WithTailingDelimiter: Boolean): String;
begin
  Result := '';
  while Assigned(aNode) do begin
    Result := aNode.Text + '\' + Result;
    aNode := aNode.Parent;
  end;
  if not WithTailingDelimiter then Delete(Result, Length(Result), 1);
end;
(*
function GetNodePath(aNode:TTreeNode; WithDelimiter: Boolean): String;
begin
  if Assigned(aNode) then begin
    if WithDelimiter then Result := aNode.Text +'\'
      else Result := aNode.Text;
    aNode := aNode.Parent;

    while assigned(aNode) do begin
      Result := aNode.text + '\' + Result;
      aNode := aNode.Parent;
    end;
  end else Result := '';  // himitsu : Zuweisung nur wenn nötig
end;
*)

(***************************************************************************
  Trägt kompletten Pfad der Parent-Nodes eines TreeView in eine StringList,
  die DataTyp erfüllen.
  Der Basis-Node selbst wird in Objects gespeichert
***************************************************************************)

procedure NodesToPathList(aTreeView: TTreeView; aStringList: TStrings; WithTailingDelimiter: Boolean;
                          DataTyp : TNodesToPathListTyp = ntpl_DataAll);
var
  i : Integer;
  guilty : Boolean;
begin
  with aTreeView do begin

    for i := 0 to Items.Count-1 do begin
      // Node ist gültig zum Eintrag in die Liste?
      case DataTyp of
        ntpl_DataNil : guilty := Items[i].Data = NIL;
        ntpl_DataAssigned : guilty := Items[i].Data <> NIL;
      else
        guilty := True; // ntpl_DataAll
      end;
      // Pfad zusammenbauen
      if guilty then
        aStringList.AddObject(GetNodePath(Items[i], WithTailingDelimiter),Items[i]);
    end;

  end;
end;

(***************************************************************************
  Findet einen Node durch Angabe des Pfadnamen
  Achtung! aPath-Wert wird innerhalb verändert

  Dank an himitsu @ Delphi-Praxis
***************************************************************************)

Function FindNodeByPath(aTreeView: TTreeView; aPath: String): TTreeNode;
Var
  Path: TArrayOfString;
  i, i2: Integer;
Begin
  Result := nil;
  if aPath='then exit;

  //Path := Mixed.Explode('\', ExcludeTrailingBackslash(aPath));
  aPath := IncludeTrailingBackslash(aPath);
  while aPath <> 'do begin
    i2 := Pos('\', aPath); // himitsu: lokale Variable
    i := Length(Path); // statt mehrfacher Funktionsaufruf
    SetLength(Path, i+1);
    Path[i] := Copy(aPath, 1, i2-1);
    Delete(aPath, 1, i2);
  end;

  Result := aTreeView.Items.GetFirstNode;
  i := 0;
  While Assigned(Result) do Begin
    //If CompareStr(Result.Text,Path[i])=0 Then Begin
    if Result.Text = Path[i] Then Begin
      If i < High(Path) Then Begin
        Inc(i);
        Result := Result.getFirstChild;
      End Else Exit;
    End Else Result := Result.getNextSibling;
  End;
End;

(***************************************************************************
  Prüft, ob in einem TreeZweig ein Node.Text bereits exitiert
  ist kein Zweig ausgewählt, prüft es die erste Ebene
***************************************************************************)

function NodeTextExistsInTwig(aTreeView: TTreeView; aParentNode: TTreeNode; aText : String): Boolean;
var
  aNode : TTreeNode;
begin
  Result := False;
  aText := AnsiUpperCase(aText); // himitsu: späterer Mehrfachaufruf verhindern
  aNode := NIL;

  // richtigen FirstNode ermitteln
  if Assigned(aParentNode) then aNode := aParentNode.GetFirstChild
    else if Assigned(aTreeView) then aNode := aTreeView.TopItem;

  // StartNode und SchwesterNodes prüfen
  while Assigned(aNode) do begin
    if AnsiUpperCase(aNode.Text) = aText then begin
      Result := True;
      Exit; // Break ginge auch, nächste aNode-Zuweisung würde verworfen
    end;
    aNode := aNode.getNextSibling;
  end;
end;

(***************************************************************************
  Prüft, ob ein NodeText schon existiert (entweder im Zweig oder ganzen Baum)
  und gibt einen UniqueNamen zurück, erweitert um [x]
  Die erste Ebene wird dabei wie ein Zweig (von Root) behandelt
***************************************************************************)

function GetUniqueNodeText(aTreeView: TTreeView; aParentNode: TTreeNode;
                           aNodeText : String; OnlyInTwig : Boolean = True): String;
var
  i : Integer;
  sl : TStringList;
begin
  Result := aNodeText;

  {<--- Prüft nur einen Zweig bzw. erste Ebene --->}
  if OnlyInTwig then begin

    i := 0;
    while NodeTextExistsInTwig(aTreeView, aParentNode, Result) do begin
      inc(i);
      Result := aNodeText+'['+IntToStr(i)+']';
    end;

  {<--- Prüft alle Nodes --->}
  end else begin

    sl := TStringList.Create;
    try
      // Namen sammeln, damit Items nicht x-mal durchlaufen werden muss
      // Aufwand relativiert sich bei großen Bäumen
      for i := 0 to aTreeView.Items.Count-1 do
        if Pos(AnsiUpperCase(aNodeText), AnsiUpperCase(aTreeView.Items[i].text)) > 0 then
          sl.Add(AnsiUpperCase(aTreeView.Items[i].text));

      // Prüfen und gg. erweitern
      i := 0;
      while sl.IndexOf(AnsiUpperCase(Result)) >= 0 do begin
        inc(i);
        Result := aNodeText+'['+IntToStr(i)+']';
      end;

    finally
      sl.Free;
    end;

  end;
end;

end.
Ich bin kein Profi, also ein kritischer Blick auf den Code schadet nicht
  Mit Zitat antworten Zitat
Benutzerbild von himitsu
himitsu

Registriert seit: 11. Okt 2003
Ort: Elbflorenz
43.140 Beiträge
 
Delphi 12 Athens
 
#2

Re: TreeViewTools (rund um Node.Text und Node-Path)

  Alt 8. Mär 2009, 11:00
hab erstmal nur kurz reingeblickt: (Änderungen mit <<< markiert)
Delphi-Quellcode:
function GetNodePath(aNode:TTreeNode; WithDelimiter: Boolean): String;
begin
  if Assigned(aNode) then begin
    if WithDelimiter then Result := aNode.Text +'\'
      else Result := aNode.Text;
    aNode := aNode.Parent;
    while assigned(aNode) do begin
      Result := aNode.text + '\' + Result;
      aNode := aNode.Parent;
    end;
  end else Result := ''; <<<<<
end;
// ist jetzt nichts Schlimmes, aber Result war sonst "sinnlos",
// da es in [i]if WithDelimiter then ...[/i] eh überschrieben wurde

Function FindNodeByPath(aTreeView: TTreeView; aPath: String): TTreeNode;
Var
  Path: TArrayOfString;
  i, i2: Integer;
Begin
  Result := nil;
  if aPath='then exit;

  //Path := Mixed.Explode('\', ExcludeTrailingBackslash(aPath));
  aPath := IncludeTrailingBackslash(aPath);
  while aPath <> 'do begin
    i2 := Pos('\', aPath); <<<<<
    i := Length(Path);
    SetLength(Path, i+1);
    Path[i] := Copy(aPath, 1, i2-1); <<<<<
    Delete(aPath, 1, i2); <<<<<
  end;

  Result := aTreeView.Items.GetFirstNode;
  i := 0;
  While Assigned(Result) do Begin
    if Result.Text = Path[i] Then Begin
      If i < High(Path) Then Begin
        Inc(i);
        Result := Result.getFirstChild;
      End Else Exit;
    End Else Result := Result.getNextSibling;
  End;
End;

function NodeTextExistsInTwig(aTreeView: TTreeView; aParentNode: TTreeNode; aText : String): Boolean;
var
  aNode : TTreeNode;
begin
  Result := False;
  aText := AnsiUpperCase(aText); <<<<<<<<<
  aNode := NIL;

  // richtigen FirstNode ermitteln
  if Assigned(aParentNode) then aNode := aParentNode.GetFirstChild
    else if Assigned(aTreeView) then aNode := aTreeView.TopItem;

  // StartNode und SchwesterNodes prüfen
  while Assigned(aNode) do begin
    if AnsiUpperCase(aNode.Text) = aText then begin <<<<<<<<<<
      Result := True;
      Exit; // Break ginge auch, nächste aNode-Zuweisung würde verworfen
    end;
    aNode := aNode.getNextSibling;
  end;
end;
Garbage Collector ... Delphianer erzeugen keinen Müll, also brauchen sie auch keinen Müllsucher.
my Delphi wish list : BugReports/FeatureRequests
  Mit Zitat antworten Zitat
Satty67

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

Re: TreeViewTools (rund um Node.Text und Node-Path)

  Alt 8. Mär 2009, 11:46
Hallo himitsu,

zu 1)... das kommt wohl, weil ich immer erst Result "initialisiere", sonst vergesse ich das. Passe ich an.

zu 2) Lokale Variable statt 3x der gleich Funktionsaufruf, übernehme ich natürlich (glaube die Art von Optimierung könnte man bei allen meinen Quelltexten machen)

zu 3) Zuweisung vorab, Mehrfachaufruf verhindert
  Mit Zitat antworten Zitat
Benutzerbild von RWarnecke
RWarnecke

Registriert seit: 31. Dez 2004
Ort: Stuttgart
4.408 Beiträge
 
Delphi XE8 Enterprise
 
#4

Re: TreeViewTools (rund um Node.Text und Node-Path)

  Alt 8. Mär 2009, 11:51
Deine Funktion GetNodePath kann man auch so schreiben :
Delphi-Quellcode:
function TreeNodePath(node: TTreeNode; delimiter: Char = PathDelim): string;
begin
  if Assigned(node) then
    Result := TreeNodePath(node.Parent, delimiter) + delimiter + node.Text
  else
    Result := '';
end;
Rolf Warnecke
App4Mission
  Mit Zitat antworten Zitat
Satty67

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

Re: TreeViewTools (rund um Node.Text und Node-Path)

  Alt 8. Mär 2009, 11:58
Rekursiv, sieht schlank aus, auch wenn ich jetzt eine Weile schauen musste, bis ich es gemerkt hab'.

Wie implementiere ich die Aufgabe, manche Node mit und mache ohne abschließenden '\' zu liefern? Außerhalb lösen?
  Mit Zitat antworten Zitat
Benutzerbild von himitsu
himitsu

Registriert seit: 11. Okt 2003
Ort: Elbflorenz
43.140 Beiträge
 
Delphi 12 Athens
 
#6

Re: TreeViewTools (rund um Node.Text und Node-Path)

  Alt 8. Mär 2009, 12:18
Schlanker mag es aussehn, aber dafür sind dort mehrere Prozeduraufrufe und Rückprünge drin und es wird ein klein bissl mehr Speicher benötigt.
Delphi-Quellcode:
function GetNodePath(aNode:TTreeNode; WithTailingDelimiter: Boolean): String;
begin
  Result := '';
  while Assigned(aNode) do begin
    Result := aNode.Text + '\' + Result;
    aNode := aNode.Parent;
  end;
  if not WithDelimiter then Delete(Result, Length(Result), 1);
end;


// falls aNode nie NIL ist, dann auch so möglich

function GetNodePath(aNode:TTreeNode; WithTailingDelimiter: Boolean): String;
begin
  if WithDelimiter then Result := aNode.Text + '\else Result := aNode.Text;
  aNode := aNode.Parent;
  while assigned(aNode) do begin
    Result := aNode.Text + '\' + Result;
    aNode := aNode.Parent;
  end;
end;
ach ja, .Parent ruft .GetParent auf, was wiederum intern einiges macht ... drum hab ich das in der Schleife nur noch einmal drin.

Zitat von Satty67:
Wie implementiere ich die Aufgabe, manche Node mit und mache ohne abschließenden '\' zu liefern? Außerhalb lösen?
Delphi-Quellcode:
function GetNodePath(Node: TTreeNode; WithTailingDelimiter: Boolean): String;
begin
  if Assigned(Node) then begin
    if WithTailingDelimiter then
      Result := GetNodePath(Node.Parent, True) + Node.Text + '\'
    else Result := GetNodePath(Node.Parent, True) + Node.Text;
  end else Result := '';
end;

// oder

function GetNodePath(Node: TTreeNode; WithTailingDelimiter: Boolean): String;
begin
  if Assigned(Node) then begin
    Result := GetNodePath(Node.Parent, True) + Node.Text;
    if WithTailingDelimiter then Result := Result + '\';
  end else Result := '';
end;
Garbage Collector ... Delphianer erzeugen keinen Müll, also brauchen sie auch keinen Müllsucher.
my Delphi wish list : BugReports/FeatureRequests
  Mit Zitat antworten Zitat
Benutzerbild von himitsu
himitsu

Registriert seit: 11. Okt 2003
Ort: Elbflorenz
43.140 Beiträge
 
Delphi 12 Athens
 
#7

Re: TreeViewTools (rund um Node.Text und Node-Path)

  Alt 8. Mär 2009, 12:31
Zitat von himitsu:
Schlanker mag es aussehn, aber dafür sind dort mehrere Prozeduraufrufe und Rückprünge drin und es wird ein klein bissl mehr Speicher benötigt.
Delphi-Quellcode:
function GetNodePath(aNode:TTreeNode; WithTailingDelimiter: Boolean): String;
begin
  Result := '';
  while Assigned(aNode) do begin
    Result := aNode.Text + '\' + Result;
    aNode := aNode.Parent;
  end;
  if not WithDelimiter then Delete(Result, Length(Result), 1);
end;


// falls aNode nie NIL ist, dann auch so möglich

function GetNodePath(aNode:TTreeNode; WithTailingDelimiter: Boolean): String;
begin
  if WithDelimiter then Result := aNode.Text + '\else Result := aNode.Text;
  aNode := aNode.Parent;
  while assigned(aNode) do begin
    Result := aNode.Text + '\' + Result;
    aNode := aNode.Parent;
  end;
end;
ach ja, .Parent ruft .GetParent auf, was wiederum intern einiges macht ... drum hab ich das in der Schleife nur noch einmal drin.

Zitat von Satty67:
Wie implementiere ich die Aufgabe, manche Node mit und mache ohne abschließenden '\' zu liefern? Außerhalb lösen?
Delphi-Quellcode:
function GetNodePath(Node: TTreeNode; WithTailingDelimiter: Boolean): String;
begin
  if Assigned(Node) then begin
    if WithTailingDelimiter then
      Result := GetNodePath(Node.Parent, True) + Node.Text + '\'
    else Result := GetNodePath(Node.Parent, True) + Node.Text;
  end else Result := '';
end;

// oder

function GetNodePath(Node: TTreeNode; WithTailingDelimiter: Boolean): String;
begin
  if Assigned(Node) then begin
    Result := GetNodePath(Node.Parent, True) + Node.Text;
    if WithTailingDelimiter then Result := Result + '\';
  end else Result := '';
end;

[add]
noch länger, aber dafür wohl noch schneller ...
Delphi-Quellcode:
Function GetNodePath(Node: TTreeNode; WithTailingDelimiter: Boolean): String;
  Var L: Integer;
    Temp: TTreeNode;
    P: PChar;

  Begin
    If Assigned(Node) Then Begin
      L := 0;
      Temp := Node;
      While Assigned(Temp) do Begin
        Inc(L, Length(Temp.Text) + 1);
        Temp := Temp.Parent;
      End;
      If not WithTailingDelimiter Then Dec(L);
      SetLength(Result, L * SizeOf(Char));
      P := PChar(Result);
      While Assigned(Node) do Begin
        MoveMemory(P, PChar(Temp.Text), Length(Temp.Text) * SizeOf(Char));
        Inc(P, Length(Temp.Text));
        Node := Node.Parent;
        If Assigned(Node) or WithTailingDelimiter Then Begin
          P^ := '\';
          Inc(P);
        End;
      End;
    End Else Result := False;
  End;
ungetestet, aber sollte so stimmen
Garbage Collector ... Delphianer erzeugen keinen Müll, also brauchen sie auch keinen Müllsucher.
my Delphi wish list : BugReports/FeatureRequests
  Mit Zitat antworten Zitat
Satty67

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

Re: TreeViewTools (rund um Node.Text und Node-Path)

  Alt 8. Mär 2009, 12:49
Also die Variante:
Delphi-Quellcode:
function GetNodePath(aNode:TTreeNode; WithTailingDelimiter: Boolean): String;
begin
  Result := '';
  while Assigned(aNode) do begin
    Result := aNode.Text + '\' + Result;
    aNode := aNode.Parent;
  end;
  if not WithTailingDelimiter then Delete(Result, Length(Result), 1);
end;
gefällt mir am Besten (rein vom Verständnis).

"WithDelimiter" ändere ich auch in with "WithTailingDelimiter", weil es ja wirklich nur um den abschließenden '\' geht.

Noch bin ich guter Hoffnung, das da noch etwas Code aus meiner Schreibe übrig bleibt
  Mit Zitat antworten Zitat
Satty67

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

Re: TreeViewTools (rund um Node.Text und Node-Path)

  Alt 8. Mär 2009, 22:15
uses TDBmain; im implementation-Teil entfernt (war das Testprogramm)
  Mit Zitat antworten Zitat
Antwort Antwort


Forumregeln

Es ist dir nicht erlaubt, neue Themen zu verfassen.
Es ist dir nicht erlaubt, auf Beiträge zu antworten.
Es ist dir nicht erlaubt, Anhänge hochzuladen.
Es ist dir nicht erlaubt, deine Beiträge zu bearbeiten.

BB-Code ist an.
Smileys sind an.
[IMG] Code ist an.
HTML-Code ist aus.
Trackbacks are an
Pingbacks are an
Refbacks are aus

Gehe zu:

Impressum · AGB · Datenschutz · Nach oben
Alle Zeitangaben in WEZ +1. Es ist jetzt 04:30 Uhr.
Powered by vBulletin® Copyright ©2000 - 2024, Jelsoft Enterprises Ltd.
LinkBacks Enabled by vBSEO © 2011, Crawlability, Inc.
Delphi-PRAXiS (c) 2002 - 2023 by Daniel R. Wolf, 2024 by Thomas Breitkreuz