Newsgroup: it.comp.lang.delphi
Titolo: Inserire sottocartelle in un TTreeNode

Vorrei inserire il contenuto di una cartella (cartelle e sottocartelle) 
nel nodo selezionato di una TreeView, in modo da ricreare la struttura ad 
albero di cartelle e sottocartelle, come Esplora Risorse (i file li 
visualizzo invece in una ListView associata).
Uso il seguente codice, ma funziona a metà, perché ad ogni cartella crea 
un sotto nodo, anche se magari entramte le cartelle sono allo stesso 
livello! Inoltre alcuni file non sono inseriti nella cartella esatta, ma 
non accade sempre... 
Ecco il codice che uso (procedura ricorsiva inserita in un metodo di 
classe):
procedure AddSubFolders(const tnSourceParent: TTreeNode; const 
strStartPath: String);
{ Aggiunge tutte le sottocartelle e i file ai dati al nodo selezionato }
var
	tnCurr: TTreeNode;
	slContents: TStringList;
	i: Integer;
begin
	slContents := nil;
	try
		tnSourceParent.Selected := True;
		if not DirectoryExists(strStartPath) then exit;
		slContents := TStringList.Create();
		FindFiles(strStartPath, '*.*', slContents, False, True, False, 
True);
		for i := 0 to slContents.Count - 1 do begin
			if FileExists(slContents[i]) then Add(slContents[i], False)
			else if DirectoryExists(slContents[i]) then begin
				tnCurr := Self.Add(slContents[i], False);
				AddSubFolders(tnCurr, slContents[i]);
			end;
		end;
	finally
		slContents.Free();
	end;
end;
Mi sapete aiutare per favore? Non ne esco... a me sembra corretto!!! :'-(
Sergio Pappalardo aka Silver Black
--- posted by geoForum on 
http://www.delphiedintorni.it

 ha scritto nel messaggio
news:DzKqc.435$pZ....@tornado.fastwebnet.it...


 Uso il seguente codice, ma funziona a metà, perché ad ogni cartella crea 
[CUT]
io invece uso questo e funziona benissimo
procedure TForm1.Button1Click(Sender: TObject);
begin
  FillTree('c:\*.*', nil);
end;
procedure TForm1.FillTree(RootDir:string; Node : TTreeNode);
var
  TempNode : TTreeNode;
  x: integer;
  SearchRec  : TSearchRec;
  DirPath, FullName, FileName : string;
begin
  DirPath:=ExtractFilePath(RootDir);
  If not DirectoryExists(DirPath) then exit;
  FileName:=ExtractFileName(RootDir);
  x := FindFirst(RootDir, faAnyFile, SearchRec);
  while x = 0 do
  begin
    If (SearchRec.Name[1] <> '.') then
    begin
      FullName:=DirPath + LowerCase(SearchRec.Name);
      TempNode := TreeView1.Items.AddChild(Node, SearchRec.Name);
      If (SearchRec.Attr and faDirectory>0) then
      begin
        FillTree(FullName+'\'+FileName, TempNode);
      end
    end;
    x := FindNext(SearchRec);
  end;
end;
è un'estratto di un'esempio più complesso che riproduce l'albero incluse le
icone dei files e delle cartelle.
Lo puoi trovare qui:
http://www.awitness.org/delphi_pascal_tutorial/source3/treeview_delphi.html
 
-- 
Ciao, Anto', [37, 143, AQ] 
MB C SC 220 CDI Magma Rot
"Di sempre cio' che senti e fai cio' che pensi."
    G.G. Màrquez

io invece uso questo e funziona benissimo
Ti ringrazio molto, ma il tuo codice mi aggiunge solo la cartella 
selezionata e non le sottocartelle... Ho provato a scaricare il loro 
esempio e funziona, ma ho preferito mettere apposto il mio codice che... 
FUNZIONA!!! Bastava aggiungere la seguente linea: 
tnSourceParent.Selected := True;
alla fine del ciclo FOR, per riselezionare il nodo padre. Infatti il mio 
metodo Add aggiunge l'elemento (cartella/sottocartella/file) al nodo 
selezionato e senza tale linea rimaneva selezionata l'ultima cartella 
aggiunta, per questo mi aggiungeva sempre i file in quest'ultima.
Il codice corretto è quindi il seguente:
procedure AddSubFolders(const tnSourceParent: TTreeNode; const 
strStartPath: String);
{ Aggiunge tutte le sottocartelle e i file ai dati al nodo 
selezionato }
var
	tnCurr: TTreeNode;
	slContents: TStringList;
	i: Integer;
begin
	slContents := nil;
	try
		tnSourceParent.Selected := True;
		if not DirectoryExists(strStartPath) then exit;
		slContents := TStringList.Create();
		Findfiles(strStartPath, '*.*', slContents, False, True, False, 
True);
		for i := 0 to slContents.Count - 1 do begin
			if FileExists(slContents[i]) then Add(slContents[i], False)
			else if DirectoryExists(slContents[i]) then begin
				tnCurr := Self.Add(slContents[i], False);
				if tnCurr <> nil then AddSubFolders(tnCurr, slContents[i];c
				tnSourceParent.Selected := True;
			end;
		finally
		slContents.Free();
	end;
end;
E sono contento di avere raggiunto la soluzione correggendo un piccolo bug 
del mio codice, piuttosto che utilizzare la pappa pronta!!! Grazie 
comunque delle vostre risposte, sicuramente mi saranno utili in altre 
occasioni.


tnSourceParent.Selected := True; [...]
attenzione ti stai legando molto all'interfaccia,
magari è una cosa voluta perchè hai scritto del codice
utile nell'evento OnChange, OnChanging o altri del
treeView, ma questo modo di fare ti potrebbe portare
problemi se sposti la procedura ricorsiva
AddSubFolders (che nella sua processazione potrebbe
essere MOLTO lenta) in un thread separato. In quanto
l'utente a quel punto avrebbe l'interfaccia libera e
potrebbe cambiarti il SelectedNode.
Io preferisco l'altra maniera ... e se uso codice,
necessario all'inserimento dei nodi, in qualche evento
del treeView, lo richiamo come procedura all'interno
della ricorsione ...
Non dovrei scrivere molto codice di più ma, in
compenso, se scritto bene, il tutto diventerebbe più
isolabile e riutilizzabile.
Mi sembra un modo più lineare di lavorare ...
comunque posso sempre sbagliarmi :)
Forse mi sarei potuto risparmiare il post :P ma mi
piaceva l'idea di esporti un mio dubbio ;)
	Ciao
	MassimoB
 
---------------------------
http:\\
www.massimobeschi.it

piaceva l'idea di esporti un mio dubbio ;)
Hai fatto benissimo a dirmelo, i confronti mi piacciono.
Quello che dici è vero, ma non sai che gestisco tutto con una classe, che 
ha "in mano" la TreeView, associata con il metodo Create. In questo modo 
la classe è generica e può essere usata in modo molto semplice, 
astraendosi completamente dall'interfaccia e dal contenuto iniziale della 
TreeView utilizzata.
Data questa premessa, ne consegue che naturalmente la classe si preoccupa 
di disabilitare la TreeView durante l'esecuzione dei metodi che la 
manipolano, in modo che l'utente non possa interagirvi.
Infine, posso assicurarti che, dai miei test empirici, la procedura è 
molto veloce, anche su migliaia di file (testata sulla mia cartella 
Musica, un migliaio di file e decine di sottocartelle, per un totale di 
più di 5 GB - meno di 10 secondi su un P3 733). Questo perchè blocco la 
visualizzazione dei file se non a fine processo.
Altre raccomandazioni? Tutti i vostri consigli sono beneaccetti, dato che 
stimo moltissimo i programmatori di questo newsgroup, che non mi hanno mai 
deluso.


visualizzazione dei file se non a fine processo. [...]
ai provato su un 200M con 64M di Ram ed un hardDisk di
annata 5400 ;) con Win95/98nonSE... c'è chi ci deve
pensare :(
Penso che dipenda anche dalla frequenza di
aggiornamento che deve avere questa FilesTree. Se la
tua applicazione vuole avere un aggiornamento
abbastanza frequente della FilesTree allora l'uso della
tua applicazione divverebbe veramente lento.
Questo se non hai già scritto una ricorsione più
leggera per l'aggiornamento ovviamente :D


leggera per l'aggiornamento ovviamente :D
Vedi, la TreeView visualizza solo la struttura delle cartelle, mentre i 
files sono visualizzati da una ListView. Inoltre blocco l'aggiornamento 
dei files durante l'aggiornamento delle cartelle, ed è la visualizzazione 
dei file che prende più tempo.
Comunque vedrò di ottimizzare, dato che la velocità non è mai abbastanza!


 ha scritto nel messaggio
news:GU3rc.1453$G%.1043@tornado.fastwebnet.it...


che non cadino due \ consecutive
Graize Giorgio, ma come spiegavo a Massimo, ho messo apposto tutto 
inserendo la riga 
  tnSourceParent.Selected := True;
subito dopo la chiamata ricorsiva. Questo per "tornare indietro" (visto 
che il mio metodo Add aggiunge i dati al nodo selezionato della TreeView 
associata alla classe (tramite il metodo Create).
