Das Problem warum es bei dir so lange dauert ist das Hinzufügen. Eigentlich ist genau das schöne an der VST, dass du die Knoten hinzufügen kannst und diese nicht direkt abgerufen werden, erst wenn du sie anzeigst. Du rufst aber unnötigerweise ValidateNode auf und führst das damit ad absurdum.
Eine Möglichkeit
Delphi-Quellcode:
type
TTreeData = class
private
FFilename: string;
FIconIndex: Integer;
public
constructor Create(const AFilename: string);
property IconIndex: Integer read FIconIndex write FIconIndex;
property Filename: string read FFilename write FFilename;
end;
TOnAddFile = procedure(const AFilename: string) of object;
TFileSearchTree = class(TThread)
private
FPath: string;
FOnAddFile: TOnAddFile;
FCurrentFile: string;
procedure DoAddFile;
protected
procedure Execute; override;
public
constructor Create(const APath: string; const AOnAddFile: TOnAddFile);
property OnAddFile: TOnAddFile read FOnAddFile write FOnAddFile;
end;
TForm67 = class(TForm)
VST: TVirtualStringTree;
ImageList1: TImageList;
procedure FormCreate(Sender: TObject);
procedure VSTGetText(Sender: TBaseVirtualTree; Node: PVirtualNode; Column: TColumnIndex; TextType: TVSTTextType;
var CellText: string);
procedure VSTGetImageIndex(Sender: TBaseVirtualTree; Node: PVirtualNode; Kind: TVTImageKind; Column: TColumnIndex;
var Ghosted: Boolean; var ImageIndex: Integer);
private
procedure AddFile(const AFilename: string);
procedure AddFileEvent(const AFilename: string);
public
end;
var
Form67: TForm67;
implementation
{$R *.dfm}
procedure TForm67.AddFileEvent(const AFilename: string);
begin
AddFile(AFilename);
end;
procedure TForm67.FormCreate(Sender: TObject);
begin
VST.NodeDataSize := SizeOf(TTreeData);
TFileSearchTree.Create('c:\windows', AddFileEvent);
end;
procedure TForm67.VSTGetImageIndex(Sender: TBaseVirtualTree; Node: PVirtualNode; Kind: TVTImageKind; Column: TColumnIndex;
var Ghosted: Boolean; var ImageIndex: Integer);
function GetIconIndex(const AFilename: string): Integer;
var
Icon: TIcon;
FileIcon: TSHFileInfo;
begin
Icon := TIcon.Create;
try
ZeroMemory(@FileIcon, SizeOf(FileIcon));
SHGetFileInfo(PChar(AFilename), 0, FileIcon, SizeOf(FileIcon), SHGFI_SYSICONINDEX or SHGFI_ICON);
Icon.Handle := FileIcon.hIcon;
Result := ImageList1.AddIcon(Icon);
finally
Icon.Free;
end;
end;
var
TreeData: TTreeData;
begin
if (Kind <> ikOverlay) and (Column = 0) then
begin
TreeData := TTreeData(Sender.GetNodeData(Node)^);
if TreeData.IconIndex < 0 then
TreeData.IconIndex := GetIconIndex(TreeData.Filename);
ImageIndex := TreeData.IconIndex;
end;
end;
procedure TForm67.VSTGetText(Sender: TBaseVirtualTree; Node: PVirtualNode; Column: TColumnIndex; TextType: TVSTTextType;
var CellText: string);
var
TreeData: TTreeData;
begin
TreeData := TTreeData(Sender.GetNodeData(Node)^);
case Column of
0:
CellText := TreeData.Filename;
end;
end;
procedure TForm67.AddFile(const AFilename: string);
var
NewNode: PVirtualNode;
begin
NewNode := VST.AddChild(nil, TTreeData.Create(AFilename));
NewNode.CheckType := ctCheckBox;
NewNode.CheckState := csCheckedNormal;
end;
{ TTreeData }
constructor TTreeData.Create(const AFilename: string);
begin
FFilename := AFilename;
FIconIndex := -1;
end;
{ TFileSearchTree }
constructor TFileSearchTree.Create(const APath: string; const AOnAddFile: TOnAddFile);
begin
inherited Create(False);
FPath := APath;
FOnAddFile := AOnAddFile;
end;
procedure TFileSearchTree.DoAddFile;
begin
FOnAddFile(FCurrentFile);
end;
procedure TFileSearchTree.Execute;
procedure FindAllFiles(ARootFolder: string; AMask: string = '*.*'; ARecurse: Boolean = True);
// von: http://www.delphipraxis.net/2235-verzeichnisse-nach-dateien-durchsuchen.html
var
SR: TSearchRec;
begin
// Implementation bis einschließlich Delphi 4
if ARootFolder = '' then
Exit;
if AnsiLastChar(ARootFolder)^ <> '\' then
ARootFolder := ARootFolder + '\';
// Implementation ab Delphi 5
ARootFolder := IncludeTrailingPathDelimiter(ARootFolder);
if FindFirst(ARootFolder + AMask, faAnyFile, SR) = 0 then
try
repeat
if SR.Attr and faDirectory <> faDirectory then
begin
FCurrentFile := ARootFolder + SR.Name;
Synchronize(DoAddFile);
end;
until FindNext(SR) <> 0;
finally
FindClose(SR);
end;
if ARecurse then
if FindFirst(ARootFolder + '*.*', faAnyFile, SR) = 0 then
try
repeat
if SR.Attr and faDirectory = faDirectory then
// --> ein Verzeichnis wurde gefunden
// der Verzeichnisname steht in SR.Name
// der vollständige Verzeichnisname (inkl. darüberliegender Pfade) ist
// ARootFolder + SR.Name
if (SR.Name <> '.') and (SR.Name <> '..') then
FindAllFiles(ARootFolder + SR.Name, AMask, ARecurse);
until FindNext(SR) <> 0;
finally
FindClose(SR);
end;
end;
begin
if Assigned(FOnAddFile) then
FindAllFiles(FPath, '*.*', True);
end;
Das ist immer noch nicht optimal, da jede Datei aus dem Thread einzeln synchronisiert und angezeigt wird. Da könnte man auch z.B. alle Dateien in einem Verzeichnis in eine Liste packen und die ganze Liste synchronisiert hinzufügen oder ähnliches. Aber das sollte als beispiel erst einmal reichen.