Delphi-PRAXiS

Delphi-PRAXiS (https://www.delphipraxis.net/forum.php)
-   GUI-Design mit VCL / FireMonkey / Common Controls (https://www.delphipraxis.net/18-gui-design-mit-vcl-firemonkey-common-controls/)
-   -   Delphi TTreeView alles dopelt, warum ? (https://www.delphipraxis.net/75041-ttreeview-alles-dopelt-warum.html)

mimi 13. Aug 2006 11:33


TTreeView alles dopelt, warum ?
 
Liste der Anhänge anzeigen (Anzahl: 1)
Hallo,
ich lese die verzeichnis strucktur ein und zwar so:
damit es nicht ewig dauert wollte ich es stückweise machen.
also habe ich folgenden
D:\Daten
D:\Spiele
D:\Programme
diese verzeichnis werden eingelesen und auch deren unterverzeichnise:
D:\Daten\unterverz.\
D:\Spiele\unterverz.\
D:\Programme\unterverz.\
und das sieht dann auch so ungefähr aus.
ich arbeite mit zwei proceduren:
Delphi-Quellcode:
procedure DirsToTreeView(Dir:String; TV:TTreeview;Item:TTreeNode; addFiles:Boolean; ChildCount:Integer);
var
  Sr: TSearchRec;
  parent:TTreeNode;
begin
  // Damit nicht ständig neugezeichnet wird
  dir:=GetDir(dir);
  // Suche nur starten wenn es ein erfolgt wahr also es keine fehler geben hat
  if findFirst(Dir + '*.*', faDirectory,sr) = 0 then begin
    repeat
      // Wenn es sich um verzeichnis handelt
      if sr.name[1] <> '.' then begin
        if ((sr.Attr and faDirectory > 0)) then begin
          item:=tv.Items.AddChild(Item,sr.name);

          Parent:=item.Parent;

          if ChildCount = 0 then begin
            ChildCount:=1;
            DirsToTreeView(dir+sr.name,tv,item,addfiles,ChildCount);
            ChildCount:=0;
          end;
          item:=parent;
        end;
      end; // if sr.name

    until FindNext(SR) <> 0;
  end;
end;
die installsiert die TreeView bzw. befüllt sie mit Verzeichnise aber halt nicht komplet:
die zweite procedure soll jetzt sobalt ich auf ein + zeichen drücke die unterverzeichnis durchsuchen und es dort emebfalls so machen also:
das dort die unterverzeichnise eingelesen werden wie oben gezeigt...
aber halt nicht alle.

Delphi-Quellcode:
procedure DirsToTV(dir:String; tv:TTreeview; item:TTreeNode;count:Integer);
var
  i:Integer;
  pfad:String;
  sr:TSearchRec;
begin
//ShowMEssage(IntToStr(count));
  for i:=0 to Item.Count-1 do begin
    pfad:= getItemPfad(tv,item.Item[i]); ;
    if findFirst(pfad + '\*.*',faDirectory,sr) = 0 then begin
      repeat
        if sr.name[1] <> '.' then begin
          if (sr.Attr and faDirectory > 0) then begin
            if item.item[i] <> NIL then begin
               tv.Items.AddChild(item.item[i],sr.name);
            end;
          end;
        end;
      until FindNext(sr) <> 0;
      FindClose(sr);
    end;
  end;
end;
und genau hier ist auch das problem bei AddChild sobalt ich das aufrufe habe ich den stamm zweimal und ich weiß nicht warum auch wenn ich oben die ShowMessage habe die sag es sein 19 einträge obwohl es nur 9 sind ich weiß einfach nicht mehr weiter.

im anahng ist die exe datei.
achaj: ich arbeitet unter "Delphi 2005 PE"

raiguen 13. Aug 2006 19:11

Re: TTreeView alles dopelt, warum ?
 
Moin :-)
Ich vermute mal (anhand Deines Beispiels), dass Du eine Verzeichnis-Explorer nachbauen möchtest...
Das ist doch relativ einfach zu machen und geht auch superflink(siehe mein Code weiter unten)

Zunächst: die doppelten Einträge sind einfach zu erklären-> im ersten Step ziehst Du dir schon die [b]gesamte[/] Verszeichnisstruktur des ausgewählten Laufwerks rein:
Code:
procedure DirsToTreeView(Dir:String; TV:TTreeview;Item:TTreeNode; addFiles:Boolean; ChildCount:Integer);
var
  Sr: TSearchRec;
  parent:TTreeNode;
begin
   ...
   item:=tv.Items.AddChild(Item,sr.name); //--Knoten zuweisen
...
   //--für den soeben erstellten Knoten gleich die Unterverzeichnisse suchen und eintragen
   DirsToTreeView(dir+sr.name,tv,item,addfiles,ChildCount);
...
end;
Ist ja prinzipiell nicht verkehrt, nur bei einer umfangreichen Struktur dauert es halt ein bischen, bis der Baum aufgebaut ist...
Im zweiten Step klickst Du auf irgendeinen Knoten, um diesen aufzumachen und die darumnterliegende Struktur anzuzeigen bzw. die Struktur einzulesen -> genau hier erscheinen dann die doppelten Einträge -> Du liest mit der zweiten Procedure nochmals die Struktur des angewählten Knotens aus, obwohl diese schon vom ersten Step vorhanden ist...

So, nun zu meinem Lösungsvorschlag:
Delphi-Quellcode:
{Hinweis: AutoExpand beim TreeView ist FALSE!!}
//--Editfeld zur Laufwerksauswahl
procedure TfrmMain.Edit2KeyPress(Sender: TObject; var Key: Char);
var Node: TTreeNode;
begin
if key=#13 then
  begin
    //--RootKnoten erstellen
    Node := TreeView1.Items.Add(nil,Edit2.Text);
    //--erste Verzeichnisebene auslesen
    VerzBaum(Edit2.Text, TreeView1, Node, false);
  end;
end;

procedure TfrmMain.VerzBaum(Dir: String; aTV:TTreeView; aItem: TTreeNode);
var
  SR: TSearchRec;
  NeuerNode: TTreeNode;
begin
  aTV.Items.BeginUpdate; //--Aufbau schneller, da nicht ständig neu gezeichnet werden muss
  if findFirst(Dir+'\*.*', faAnyFile,SR) = 0 then
    repeat
      if (SR.Name <> '.') and (SR.Name <> '..') and (sr.Attr and faDirectory > 0) then begin
          NeuerNode := aTV.Items.AddChild(aItem,SR.Name);
          NeuerNode.HasChildren := True; //erstmal setzen
      end;
    until FindNext(SR) <> 0;
  FindClose(SR);
  aTV.Items.EndUpdate; //--neue Knoten anzeigen

  //--Markierung entsprechend setzen
  aItem.HAsChildren := (aItem.Count>0);
end;

//--Knoten expandieren bzw Struktur einlesen und Baum aufbauen
procedure TfrmMain.TreeView1Expanding(Sender: TObject; Node: TTreeNode;
  var AllowExpansion: Boolean);

var ElternKnoten: TTreeNode;
    Pfad: String;
begin
  //--wenn noch keine Unterknoten(Kinder) existieren
  if Node.GetFirstChild = nil then
     begin
      //--alle Parents auslesen bis zur Root und somit den Pfadnamen zusammensetzen
      Pfad := Node.Text;
      ElternKnoten := Node.Parent;
      while ElternKnoten <> nil do begin
        Pfad := ElternKnoten.Text+ '\' + Pfad ;
        ElternKnoten := ElternKnoten.Parent;
      end;
      VerzBaum(Pfad, TreeView1, Node, false);
      //AllowExpansion := True;
  end;
end;

procedure TfrmMain.TreeView1MouseUp(Sender: TObject; Button: TMouseButton;
  Shift: TShiftState; X, Y: Integer);
      { Dateien aus Verzeichnis mit entsprechender MAske auslesen }
      procedure DateiListe(sPfad, sMaske: String; aList: TListBox);
        var SR: TSearchRec;
            Pfad: String;
      begin
        Pfad := IncludeTrailingBackSlash(sPfad);
        if FindFirst (PChar(Pfad+ sMaske), faAnyFile, SR) = 0 Then
          repeat
            if (SR.Name <> '.') and (SR.Name <> '..') Then
            aList.Items.Add(SR.Name);
          until FindNext (SR ) <> 0;
        FindClose(SR);
      end;


  var aNode, ElternKnoten: TTreeNode;
    Pfad: String;
begin
  ListBox1.Clear;
  aNode := TreeView1.Selected;
  //--feststellen, ob MausKlick auf einem Knoten erfolgte
  if (htOnItem in TreeView1.GetHitTestInfoAt(X,Y)) then
    begin
      Pfad := aNode.Text;
      ElternKnoten := aNode.Parent;
      while ElternKnoten <> nil do begin
        Pfad := ElternKnoten.Text+ '\' + Pfad ;
        ElternKnoten := ElternKnoten.Parent;
      end;
      DateiListe(Pfad, '*.*', ListBox1);
  end;
end;
Das Beispiel habe ich bewusst einfach gestrickt (mit den guten D5 *grins*) um das Ganze nachvollziehbar zu machen (hoff ich doch, dass es mir gelungen ist...)
Wünsche viel Erfolg beim 'studieren' und probieren...
:hi: an meine alte Heimat (sofern es OL ist)

mimi 13. Aug 2006 22:25

Re: TTreeView alles dopelt, warum ?
 
vielen dank für deinen code habe ihn gerade ausbrobiert *G* solltes du als tip in die code lib einfügen ....

scheint bis jetzt alles zu klappen.
den teil den ich raußkopiert habe...

deine beschreibung für mein problem jedoch kann ich nicht ganz nachvollziehn:
die forschleife sollte doch alle unterkonten durchgehen aber nicht alle doppelt dastellen...

mimi 13. Aug 2006 22:41

Re: TTreeView alles dopelt, warum ?
 
was noch schön währe, wenn nur ein + gezeichnit wird wenn auch unterverzeichnise hatte:
weiß du wie ich meine ?

mimi 14. Aug 2006 16:28

Re: TTreeView alles dopelt, warum ?
 
habe das problem mit hilfe diese änderungen selbst behäben können *G*

Delphi-Quellcode:
function TForm2.GetAnderDir(dir:String):boolean;
var
  sr:TSearchRec;
  ok:Boolean;
begin
  ok:=False;
  if findFirst(Dir+'\*.*', faAnyFile,SR) = 0 then begin
    repeat
      if (sr.Name[1] <> '.') and (sr.Attr and faDirectory > 0) then begin
       // ShowMessage(sr.name);
        ok:=True;

        break;
      end;
    until FindNext(Sr) <> 0;
  end;
  FindClose(sr);
  result:=ok;
end;

procedure TForm2.VerzBaum(Dir: String; aTV:TTreeView; aItem: TTreeNode);
var
  SR: TSearchRec;
  NeuerNode: TTreeNode;
begin
  aTV.Items.BeginUpdate;
  if findFirst(Dir+'\*.*', faAnyFile,SR) = 0 then
    repeat
      if (sr.Name[1] <> '.') and (sr.Attr and faDirectory > 0) then begin
          NeuerNode := aTV.Items.AddChild(aItem,SR.Name);

          NeuerNode.HasChildren := GetAnderDir(dir + '\' +NeuerNode.text);
      end;
    until FindNext(SR) <> 0;
  FindClose(SR);
  aTV.Items.EndUpdate;
//  aItem.HAsChildren := aItem.count > 0;
end;
Diese code durch sucht einmal das hauptverzeichnis dann schaut die procedur GetAnderDir in das nächte verzeichnis rein um so diese + zu setzten wenn es unterverzeichnise gibt.. ich hoffe ihr könnte mir folgen.....

vielen dank für die hilfe !

Edit: noch was vergeesen:
du schreibst immer: if (SR.Name <> '.') and (SR.Name <> '..') Then
aber es würde reichen if sr.name[1] <> '.' then

raiguen 15. Aug 2006 09:43

Re: TTreeView alles dopelt, warum ?
 
:thumb: Schön, dass Du meine Änderungen übernommen hast und sogar daraufhin noch eine Schritt weiter gegangen bist :)
Nun, es stellt sich due Frage, wie schnell der Verzeichnisbaum aufgebaut werden soll: scheibchen weise, also immer nur die benötigte Struktur oder gleich vollständig mit allen Strukturen!
Im ersten Fall hat man natürlich das '+' auch an den Knoten, die evtl. keine weiteren Kinder haben - gut, ein Klick vergeblich, aber das '+' verschwindet dann ja...
Der zweite Fall prüft, ob evtl mindest ein Unterverzeichnis vorhanden ist...nimmt also etwas Zeit in Anspruch (bei einem Verzeichnis, was tonnenweise nur Dateien und kein UVZ hat, dauert das natürlich...), um evtl das '+' anzuzeigen.. Nun, dann kann ich ja auch gleich die komplette Struktur einlesen ;-) Nichts für ungut, wollte halt nur meine Gedanken diesbezüglich kundtun.

Das hier kannst Du noch etwas verbessern:
Delphi-Quellcode:
function TForm2.GetAnderDir(dir:String):boolean;
var
  sr:TSearchRec;
begin
  RESULT := False; //<<--vorbelegen
  if FindFirst(Dir+'\*.*', faAnyFile,SR) = 0 then
    repeat
      RESULT := (sr.Name[1] <> '.') and (sr.Attr and faDirectory > 0)
    until RESULT or (FindNext(sr) <> 0); //<--Abbruch bei RESULT=True oder wenn Verzeichnis komplett durch
  FindClose(sr);
end;

mimi 15. Aug 2006 16:12

Re: TTreeView alles dopelt, warum ?
 
vielen dank für dein tip mit der verbesserung an der funktion mein ziel ist eine schneller einlesen der verzeichnis strucktur so wie im Explorer selbst dort sind auch nur + zeichen wenn es mind. ein unterverzeichnis gibt... mehr möchte ich garnicht erreichen....

ich habe von einer methode gehört verzeichnise schneller einzulesen über
irgenwelch IDs oder so.... evlt. weißt ja einer mehr darüber...

evlt. kann ich ja auch die gleichen funktionen nutzen wie der explorer....

nuzte ja schon die systemiconlist vom explorer *G*

edit:
kennst du ihr seiten die sich mit sowas befassen(auf deutsch) so mit dem system Dateisystem *G*

ChrisE 15. Aug 2006 16:24

Re: TTreeView alles dopelt, warum ?
 
Hallo raigun, hallo mimi,

also das mit dem '+' ist so ne Sache, dass stimmt. Aber wenn man in der Methode GetAnderDir mit FindFirst gleich nur nach Verzeichnissen suchen läßt, sollte es schneller gehen. Das sieht dann so aus:
Delphi-Quellcode:
function TForm2.GetAnderDir(dir:String):boolean;
var
  sr:TSearchRec;
begin
  RESULT := False; //<<--vorbelegen
  if FindFirst(Dir+'\*.*', faDirectory,SR) = 0 then //<<--faDirectory sollte hier die Lösung sein
    repeat
      RESULT := (sr.Name[1] <> '.');
    until RESULT or (FindNext(sr) <> 0); //<--Abbruch bei RESULT=True oder wenn Verzeichnis komplett durch
  FindClose(sr);
end;
Ich denke das dürfte beide Seiten zufrieden stellen. Ich bin mir aber nicht 100% sicher, ob das dann wirklich schneller ist. Hängt davon ab, wie FindFirst/FindNext arbeiten. Sollte man mal testen :-)

Gruß, Chris

//Edit: Irgendwie werden die '<' und '>' im Quelltext-Tag durch das Zitat in das HTML-Äquivalent geändert -> &lt; oder &gt; Das verbessert :-)

mimi 15. Aug 2006 16:29

Re: TTreeView alles dopelt, warum ?
 
danke für die verbesserung. habe sie eingebaut... mein ziel ist es daraus eine funktion zu schreiben evlt. auch eine komponenten die die Explorers änlichsieht aber mehr kann als die komponenten die unter beispiele zu finden sind z.b. das mit den checkboxen und den 3 zuständen *G*


Alle Zeitangaben in WEZ +1. Es ist jetzt 00:35 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