Einzelnen Beitrag anzeigen

Benutzerbild von jaenicke
jaenicke

Registriert seit: 10. Jun 2003
Ort: Berlin
9.650 Beiträge
 
Delphi 11 Alexandria
 
#12

AW: VirtualStringTree - Nodes hinzufügen

  Alt 24. Mär 2014, 06:20
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.
Sebastian Jänicke
AppCentral

Geändert von jaenicke (24. Mär 2014 um 06:22 Uhr)
  Mit Zitat antworten Zitat