Delphi-PRAXiS
Seite 1 von 2  1 2      

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/)
-   -   VirtualStringTree - Nodes hinzufügen (https://www.delphipraxis.net/179669-virtualstringtree-nodes-hinzufuegen.html)

d7user1 23. Mär 2014 21:08

VirtualStringTree - Nodes hinzufügen
 
hallo, nach einigen stunden habe ich es endlich hinbekommen die komponente VST zu installieren.
ich bin aber irgendwie schockiert. denn die komponente ist so dermaßen mächtig und doch möchte ich doch nur Nodes hinzufügen.

mit einer listview ging es so:
Delphi-Quellcode:
var MeinItem: TListItem;
begin
 MeinItem:= ListView1.Items.Add;
 MeinItemChecked := True;

 MeinItemCaption := 'Item Caption';
 MeinItemAdd('SubItem Caption');
end;
wie bekomme ich das mit der VST so hin? ich habe die VST schon im Stil eines ListView (vsReport) mit zwei Spalten.
aber wie füge ich etwas hinzu =/

d7user1 23. Mär 2014 21:47

AW: VirtualStringTree - Nodes hinzufügen
 
update:
ich schaffe es mittlerweile nodes aus einer dateiliste hinzuzufügen, diese korrekt und farblich darzustellen.
das funktioniert alles wunderbar und schnell.

doch wenn ich GetImageIndex verwende ist die VST sehr sehr träge und langsam. zudem werden nicht alle icons angezeigt.

die systemicons hole ich so:
Delphi-Quellcode:
  // private deklariert
 hImgSm: HIMAGELIST;
 aFileIcon: TSHFileInfo;

// ...

// OnCreate:
 hImgSm := HIMAGELIST(SHGetFileInfo('', 0, aFileIcon, SizeOf(aFileIcon), SHGFI_SYSICONINDEX or SHGFI_ICON));
 if (hImgSm <> 0) then
  ImageList1.Handle := hImgSm;
 ImageList1.ShareImages := True;
 VST.Images := ImageList1;

// ...

procedure TForm1.VSTGetImageIndex(Sender: TBaseVirtualTree; Node: PVirtualNode; Kind: TVTImageKind;
 Column: TColumnIndex; var Ghosted: Boolean; var ImageIndex: integer);
var
 Data: PTreeData;
begin
 Data := VST.GetNodeData(Node);

 begin
  ZeroMemory(@aFileIcon, SizeOf(aFileIcon));

  if SHGetFileInfo(PChar(Data.sFileName), 0, aFileIcon, SizeOf(aFileIcon), SHGFI_SYSICONINDEX or SHGFI_ICON) <> 0
  then
   begin
    ImageIndex := aFileIcon.iIcon;
   end;
 end;
end;
komischerweise sind auch nur 7 icons in der ImageList zu anfang.

Sir Rufo 23. Mär 2014 22:29

AW: VirtualStringTree - Nodes hinzufügen
 
Lerne von denen, die das professionell machen ;)

Wenn ich mir den Windows-Explorer anschaue, dann werden dort erst nur die Dateinamen angezeigt und einen kleinen Augenblick später erscheinen die Icons (sieht man sehr schön, wenn die Kiste mal gut ausgelastet ist).

Die Icons und andere Zusatzinformationen werden per Thread geladen und dann nach und nach erst angezeigt.

Popov 23. Mär 2014 23:12

AW: VirtualStringTree - Nodes hinzufügen
 
Zitat:

Zitat von Sir Rufo (Beitrag 1253176)
Lerne von denen, die das professionell machen ;)

Wenn ich mir den Windows-Explorer anschaue, dann werden dort erst nur die Dateinamen angezeigt und einen kleinen Augenblick später erscheinen die Icons (sieht man sehr schön, wenn die Kiste mal gut ausgelastet ist).

Jajn. Ich kann mich noch bei Windows 95 erinnern, da wurden die alle Icons eigentlich direkt geladen (ob im ersten Gang oder per Thread). Auf jeden Fall konnte da der Explorer sehr langsam sein. Das Problem hat man bald beseitigt, und so wie ich es beobachten konnte wurde zuerst ein 08/15 Standard-Icon zugewiesen. Erst im zweiten Durchlauf wurde der richtige Icon nachgeladen und korrigiert.

Wie das jetzt ist weiß ich nicht, dafür sind die Rechner zu schnell, aber gelegentlich bin ich der Meinung noch einen Standard-Icon für kurze Zeit zu sehen.

In Grunde ist das aber das gleiche, denn ob man kein Icon zuweist oder ein Standard-Icon, ist ja die gleiche Zeit.

d7user1 23. Mär 2014 23:13

AW: VirtualStringTree - Nodes hinzufügen
 
ok das werde mir mal angucken. ich habe es bereits etwas umgestellt:

Delphi-Quellcode:
procedure TForm1.VSTGetImageIndex(Sender: TBaseVirtualTree; Node: PVirtualNode; Kind: TVTImageKind;
 Column: TColumnIndex; var Ghosted: Boolean; var ImageIndex: integer);
var
 Data: PTreeData;
 Icon: TIcon;
begin
 Data := VST.GetNodeData(Node);

 if (not Data.bUpdated) and (Column = 0) then
  begin
   Icon := TIcon.Create;

   ZeroMemory(@aFileIcon, SizeOf(aFileIcon));

   SHGetFileInfo(PChar(Data.sFileName), 0, aFileIcon, SizeOf(aFileIcon), SHGFI_SYSICONINDEX or SHGFI_ICON);
   Icon.Handle := aFileIcon.hIcon;

   ImageIndex := ImageList1.AddIcon(Icon);

   Data.bUpdated := True;
   Icon.Free;
  end;
end;
mit diesem gut war alles in ordnung. aber, ich weiß nicht seit wann, seit geraumer zeit sind die icons nicht mehr sichtbar. sie blitzen nur auf wenn ich scrolle.

ein wort zu dem bUpdated: wenn ich das nicht hinzufüge, dann "zeichnet" mein prozessor sich tot (cpu-last konstant 100).

Wishmaster 23. Mär 2014 23:15

AW: VirtualStringTree - Nodes hinzufügen
 
Hi.

wenn du versuchst Windows-Explorer nachzubauen, es gibt schon eine fertige lösung dafür. und zwar die Mustangpeak Components die sind open Source!:thumb:

d7user1 23. Mär 2014 23:19

AW: VirtualStringTree - Nodes hinzufügen
 
Liste der Anhänge anzeigen (Anzahl: 1)
danke für den zipp aber das versuche ich nicht =)

zu meinem problem mit den icons die verschwunden sind und nur auftauchen wenn ich scrolle: siehe screenshot.

der rot markierte kasten ist ein screenshot genau dann wann ich schnell scrolle.

P.S.: und warum die CheckBox in column 1 ist und nicht in 0 weiß ich auch nicht =/

daten in treeview bringen:
Delphi-Quellcode:
var
 TreeData: TTreeData;
// ...
 VST.NodeDataSize := SizeOf(TTreeData);

 TreeData.a:= sl.Strings[i];
 TreeData.b:= IntToStr(getFileSizeA(TreeData.sFileName));
 TreeData.c:= DateTimeToStr(getFileLastModified(TreeData.sFileName));
 TreeData.d:= '=>';
 TreeData.e:= sl.Strings[i];
 TreeData.f:= '';
 TreeData.g:= '';

 TreeData.bUpdated := False;

 AddVSTStructure(VST, TreeData);

// ...
function AddVSTStructure(aVST: TVirtualStringTree; aRecord: TTreeData): PVirtualNode;
var
 Data: PTreeData;
begin
 Result := aVST.AddChild(nil);

 Result.CheckType := ctCheckBox;
 Result.CheckState := csCheckedNormal;

 Data := aVST.GetNodeData(Result);
 aVST.ValidateNode(Result, False);
 Data^ := aRecord;
end;

Sir Rufo 23. Mär 2014 23:20

AW: VirtualStringTree - Nodes hinzufügen
 
@Popov

Ich bezog mich schon auf die aktuelleren Windows-Versionen ;)

So ist es, erst ist dort ein Standard-Icon und dann wird das übermalt/ersetzt.

Popov 23. Mär 2014 23:21

AW: VirtualStringTree - Nodes hinzufügen
 
Delphi-Quellcode:
      SHGetFileInfo(PChar(Data.sFileName), 0, aFileIcon, SizeOf(aFileIcon), SHGFI_SYSICONINDEX or SHGFI_ICON);
      Icon.Handle := aFileIcon.hIcon;

      ImageIndex := ImageList1.AddIcon(Icon);
Hier sieht man, dass du dein Icon direkt liest und speicherst. Das kostet Zeit. Ich habe in dem anderen Thread doch dieses Beispiel gepostet. Eine Seite weiter habe ich paar Änderungen gepostet. Da greift das Beispiel auf die ImageListe vom System und holt sich nur noch den ImageIndex. Guck dir das mal an. Zumindest brauchst du den Ordner-Icon nicht zig mal zu laden, sondern nur einmal.

d7user1 23. Mär 2014 23:24

AW: VirtualStringTree - Nodes hinzufügen
 
das mit dem system-icon hatte ich vorher in einer listview schon eingesetzt. aber komischerweise werden bei der VST ungefähr 90% der icons nicht geladen.

momentan habe ich eh das problem dass gar keine icons angezeigt werden und ich verstehe nicht wieso (siehe posting open mit screenshot).

ich bin echt zufrieden mit dieser komponente. aber es gibt viele dinge die ich vermisse und ich habe keine ahnung wie man das macht. z.b. vermisse ich MeinItem.SubItemImages[X] usw.
generell. zudem wird meine checkbox nicht korrekt positioniert.

leider weiß ich nicht wie man eine checkbox bei virtuellem modus in eine listiew zeichnet. dann würde ich VST nicht nutzen müssen.

siehe hier: http://www.delphipraxis.net/179658-l...heckbox-2.html

d7user1 24. Mär 2014 01:08

AW: VirtualStringTree - Nodes hinzufügen
 
kleiner zwischenbericht:

- checkbox ist nun korrekt positioniert, dank dem property "MainColumn".
- die items werden nun dank dieses threads korrekt angezeigt und verschwinden auch nicht mehr: http://www.delphipraxis.net/152062-v...imagelist.html .

das andere problem mit den images in den anderen columns habe ich auch bereits gelöst.


wenn ich alle dateien und verzeichnisse aus C:\Windows\System32 in eine stringliste lade und die VST dann mit nodes fülle (listview-artig mit 6 spalten) dauert das ganze nun 4 sekunden.
mit einer listview dauert das mehr als 20.
ich füge nicht nur hinzu ich ändere auch schrift- und hintergrundfarben manchmal + es sind checkboxen vorhanden.

bei biden varianten dauert die erstellung der stringliste rund 400ms.

sind 4 sekunden für alles in ordnung oder ist das für 13000 einträge mit schöner darstellung zu lange?

jaenicke 24. Mär 2014 05:20

AW: VirtualStringTree - Nodes hinzufügen
 
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. ;-)

Popov 24. Mär 2014 05:56

AW: VirtualStringTree - Nodes hinzufügen
 
@ d7user1

Alles dauert seine Zeit. Das Lesen der 13000 Dateien dauert nur ein Augenblick, das Erstellen der passenden Objekte und sogar sortieren geht auch ganz schnell, selbst das Erstellen der Items. Aber kaum packst du die ListView an (vermutlich auch Virtual TreeView) um Daten anzulegen, dauert es Zeit. Das zuweisen aller Caption's ungleich "" dauert fast 1,5 Sekunden. Das Zuweisen der ImageIndex's ungleich 0 dauert etwa 2,5 Sekunden. Womit wir bei 4 Sekunden wären. Und die SubItems, selbst wenn leer, dauert auch seine Sekunden.

Das bedeutet, die 13000 Dateien lesen und die gleiche Anzahl Objekte und Items anzulegen (plus sortieren) dauert nur paar Millisekunden, der Rest kostet Zeit.

Ich hab gerade mein Beispiel insoweit geändert, dass zuerst alle Items angelegt werden, ohne eine Zuweisung. Der Rest wird beim Anzeigen der Items gefüllt. Also nicht wie im ersten Beispiel nur die Subitems, sondern alles. Das Ergebnis bei 13000 Dateien sind 265 Millisekunden.

Ob das alles noch so seinen Sinn macht sein dahingestellt, ist einfach nur ein Test.

nuclearping 24. Mär 2014 07:14

AW: VirtualStringTree - Nodes hinzufügen
 
Zitat:

Zitat von d7user1 (Beitrag 1253186)
aber es gibt viele dinge die ich vermisse und ich habe keine ahnung wie man das macht. z.b. vermisse ich MeinItem.SubItemImages[X].

[...]

leider weiß ich nicht wie man eine checkbox bei virtuellem modus in eine listiew zeichnet. dann würde ich VST nicht nutzen müssen.

Unterschätze den VST nicht. Wie in dem anderen Thread schon gesagt hat er eine gewisse steile Lernkurve, aber wenn's einmal richtig Klick gemacht hat, wie mächtig der VST und was du alles damit machen kannst, wirst du feststellen, dass du dich mit Komponenten wie TListView und / oder TTreeView in der Steinzeit bewegt hast. Also gib dir Zeit, den Umgang zu lernen und zu verstehen und setze dich nicht unter Druck. :mrgreen:

Wie der Name schon sagt ist der "Virtual Tree View" virtuell. Also es gibt da keinen direkten Zugriff auf Knoten oder Unterknoten.
ItemIndex-Images werden auch nicht direkt zum Baum gespeichert, sondern "On Demand" mittels GetNodexIndex geholt. Das hat den Vorteil, dass dadurch der VST nicht an eine Struktur gebunden ist, sondern du alle möglichen Daten mit dem Baum verknüpfen und je nach Bedarf nach deinen eigenen Vorstellungen darstellen kannst.

Auf einzelne Knoten (und deren Daten) kannst du somit auch nicht direkt über VST.Node[X] zugreifen, sondern müsstest erst durch den Baum iterieren. Entweder per Hand mit
Delphi-Quellcode:
VST.GetFirst ... while ... VST.GetNodeData ... Daten mit Suchparametern vergleichen ... end VST.GetNext
, bzw.
Delphi-Quellcode:
GetFirstSibling
,
Delphi-Quellcode:
GetNextSibling
, usw. Oder per
Delphi-Quellcode:
OnIncrementalSearch
-Event und dann mit VST.IterateSubTree.

d7user1 24. Mär 2014 12:21

AW: VirtualStringTree - Nodes hinzufügen
 
hallo, popov, fügst du die daten aus C:\Windows\System32 in deine liste hinzu? und wenn ja, ist es noch immer das beispiel aus deinem anderen thread? denn das war nicht rekursiv meine ich und es waren glaube ich etwas mehr als 2000 daten.

ich habe gerade mal geguckt. daten sammeln (C:\Windows\System32 rekursiv) und diese in records zu speichern ohne daten in der VST anzuzeigen dauert bei mir etwas mehr als 700ms.
man darf nicht vergessen dass ich noch OnPaintText und OnAfterItemErase verwende und dort mit Font.Color und Brush rumgespielt wird.


zu deinem beispiel jaenike:
ich mache alles genau so wie du außer dass ich das nicht auf einen thread ausgelagert habe und dass ich die nodes so erzeuge:
Delphi-Quellcode:
 Node := aVST.AddChild(nil);
 Node.CheckType := ctCheckBox;
 Node.CheckState := csCheckedNormal;

 Data := aVST.GetNodeData(Node);
 Data^ := aRecord;
laut dem post von Popov sind 4 sekunden also normal für das alles was ich mache?

p.s.: selbst wenn ich die Icon in der VST weglasse und die Zellentexte nicht zuweise duaert es bei mir 700ms.
ich glaube der lädt die Icons und die Zellentexte von haus aus erst wenn sie gebracht werden.


hier eine kleine zeitmessung für C:\Windows\System32 NICHT rekursiv:
- das lesen der daten dauert bei mir ungefähr 60ms.
- das erstellen der records ohne nodes zu erzeugen etwa 600ms
- das erstellen der records mit nodes zu erzeugen etwa 650ms
- und alles zusammen mit erstellen und freigeben der dateiliste, BeginUpdate, EndUpdate etwa 700ms.

ist das so in ordnung?


großes edit:
ich weiß jetzt warum das 4 sekunden dauert. beim erstellen meiner records nutze ich einmal IntToStr(getFileSizeA()) und einmal DateTimeToStr(getFileLastModified()).
ohne IntToStr(getFileSizeA()) dauert es nur 1.5 sekunden und ohne DateTimeToStr(getFileLastModified()) dauert es nur 3.3 sekunden.
ohne beides dauert alles zusammen plus anzeigen der 13.000 dateien 400ms.

meine zwei funktionen sehen so aus:
Delphi-Quellcode:
function getFileSizeA(const FileName: string): Int64;
var
 SR: TSearchRec;
begin
 Result := 0;

 if not FileExists(FileName) then
  Exit;

 if FindFirst(FileName, faAnyFile and not faDirectory, SR) = 0 then
  try
   Result := SR.Size;
  finally
   SysUtils.FindClose(SR)
  end;
end;

function getFileLastModified(const FileName: string): TDateTime;
var
 SR: TSearchRec;
 SystemTime: TSystemTime;
 NewWriteTime: TFileTime;
begin
 Result := 0;

 if FindFirst(FileName, faAnyFile, SR) = 0 then
  try
   if (Windows.FileTimeToLocalFiletime(SR.FindData.ftLastWriteTime, NewWriteTime) and
     Windows.FileTimeToSystemTime(NewWriteTime, SystemTime)) then
    Result := Encodedate(SystemTime.wYear, SystemTime.wMonth, SystemTime.wDay) +
     Encodetime(SystemTime.wHour, SystemTime.wMinute, SystemTime.wSecond, SystemTime.wMilliseconds);
  finally
   SysUtils.FindClose(SR)
  end;
end;

jaenicke 24. Mär 2014 12:48

AW: VirtualStringTree - Nodes hinzufügen
 
Wobei das Zeichnen usw. egal ist, da das ja nur die tatsächlich angezeigten Knoten betrifft.

Was bei dir aber noch fehlt ist ein BeginUpdate...EndUpdate, denn dadurch dauert das Hinzufügen der Knoten sehr viel länger.

Wenn man den Thread noch ändert und die Dateien häppchenweise statt einzeln übergibt plus BeginUpdate...EndUpdate sollte das ganze quasi sofort initial angezeigt werden (und dann natürlich noch kurz nachladen).

Der übliche Weg sieht übrigens so aus, dass man immer nur die Dateien der aktuellen Ebene anzeigt und beim Aufklappen die Ebene darunter einliest. So sollte es keinerlei Verzögerungen geben, es sei denn du hast Verzeichnisse mit enorm vielen Dateien.

Popov 24. Mär 2014 13:14

AW: VirtualStringTree - Nodes hinzufügen
 
Liste der Anhänge anzeigen (Anzahl: 1)
Zitat:

Zitat von d7user1 (Beitrag 1253229)
hallo, popov, fügst du die daten aus C:\Windows\System32 in deine liste hinzu? und wenn ja, ist es noch immer das beispiel aus deinem anderen thread? denn das war nicht rekursiv meine ich und es waren glaube ich etwas mehr als 2000 daten.

Jajn, es ist das Beispiel, aber ich hab es zwei mal angepasst. Auch habe ich mir zum Testen ein Ordner mit 13000 Dateien erstellt. Also die 260 ms beziehen sich auf die 13000 Dateien. Ich hab alles nur verlagert (ich hänge mal das Beispiel dran).

Und ja, es ist nicht rekursiv, denn es sollte nur ein Ordner gelesen werden. Ich denke mir aber, dass es keinen besonderen Unterschied macht wenn man den gesamten Inhalt liest, inkl. Unterordner. Trotzdem, auch wenn ich das so hin gekriegt habe, es ist eher nur just4fun. Ich hab noch nie mit virtuellem ListView gearbeitet, evtl. ist es für die Aufgabe besser geeignet.

Was das Andere angeht, Total Commander hatte bis (mindestens) Version 5.5 die Möglichkeit einen Verzeichnis-Baum auszugeben. Um das zu laden hat er zum Schluss fast immer eine Minute gebraucht. Aber man läd nun mal nicht alles auf einmal, vor allem bei TreeView. Das dauert zu lange.

Popov 24. Mär 2014 13:33

AW: VirtualStringTree - Nodes hinzufügen
 
Zitat:

Zitat von d7user1 (Beitrag 1253229)
Delphi-Quellcode:
function getFileSizeA(const FileName: string): Int64;
var
 SR: TSearchRec;
begin
 Result := 0;

 if not FileExists(FileName) then
  Exit;

 if FindFirst(FileName, faAnyFile and not faDirectory, SR) = 0 then
  try
   Result := SR.Size;
  finally
   SysUtils.FindClose(SR)
  end;
end;

Das kannst du anders machen. Mal unabhängig davon ob es Sinn macht FindFirst für jede einzelne Datei FindFirst neu zu bemühen, sowie SR.Size maximal eine 32 Bit Größe ausgibt (also alles über 2 GByte falsch wiedergibt), womit Int64 unnötig ist, ist in Code FileExists nicht nötig.

FindFirst sucht ja bereits nach dem Namen der Datei, findet es nicht, geht sie nicht in der Block rein (hier try finally), sondern übergeht ihn. Somit kann man sich die FileExists Abfrage sparen, sie kostet nur Zeit.

SR.Size gibt u. U. die falsche Dateigröße zurück, denn es ist Integer. Solange du unter 2 GByte bleibst, merkst du nichts. Die richtige Größe steckt in FindData. Hier die Formel:

Delphi-Quellcode:
x := Int64(SR.FindData.nFileSizeLow) or (Int64(SR.FindData.nFileSizeHigh) shl 32);
//
Ansonsten wird hier jede Datei anscheinend zwei mal angepackt - zuerst um den Namen zu lesen, später noch mal um die Größe zu erfahren. Dabei enthält TSearchRec schon beim ersten Zugriff alle Infos.

jaenicke 24. Mär 2014 14:12

AW: VirtualStringTree - Nodes hinzufügen
 
Zitat:

Zitat von Popov (Beitrag 1253239)
SR.Size gibt u. U. die falsche Dateigröße zurück, denn es ist Integer.

Bei Delphi 7 war das damals so.
Heute ist es ein Int64 Wert.

Popov 24. Mär 2014 14:20

AW: VirtualStringTree - Nodes hinzufügen
 
Gibt SR.Size (bei aktuellen Delphis) auch den korrekten Wert an (> 2GB)?

Popov 24. Mär 2014 14:29

AW: VirtualStringTree - Nodes hinzufügen
 
@d7user1

Weil es mich interessierte, habe ich die 13000 Daten in ListView eingelesen, wobei ich das LV virtuell nutzte. Ist alles in 31 ms erledigt (inkl. lesen, sortieren, usw).

d7user1 24. Mär 2014 15:17

AW: VirtualStringTree - Nodes hinzufügen
 
hallo. genau das habe ich gestern auch einmal getan. die zeit weiß ich nicht mehr aber es war sehr schell. schneller als der VirtualStringTree.
das einzige was mich störte ist dass ich checkboxen gebraucht habe, ich die aber selbst nicht zeichnen kann. und ich bin sicher genau da, beim zeichnen der checkboxen, wird die listview wieder sehr langsam.

mein code ist momentan so weit angepasst dass das einlesen von 13000 dateien + diverses zeichnen von bestimmten nodes + dateigrößenbestimmung und datumsumwandung in etwa 450ms erledigt ist. dabei erledige ich das bestimmen der dateigröße und das umwandeln des dateidatums im OnGetText-Event statt wie zuvor beim erstellen der nodes.
beim erstellen der nodes dauert es 4 sekunden.
kleiner vergleich: dasselbe mit einer listview + checkboxen dauert etwa 25 sekunden.

DeddyH 24. Mär 2014 15:36

AW: VirtualStringTree - Nodes hinzufügen
 
Wie schon gesagt, Du könntest Dir auch mal das NextGrid anschauen, das ist IMO etwas einfacher zu handhaben als der VST. Die Versionen für Delphi 6 und 7 sind Freeware.

Popov 24. Mär 2014 17:38

AW: VirtualStringTree - Nodes hinzufügen
 
@d7user1

Ok, das ist u. U. mit etwas Arbeit verbunden, da die CheeckBoxes tatsächlich nicht gezeichnet werden. Aber das stellt sich die Frage was schneller ist - sich die Kenntnisse über eine neue Komponente aneignen oder CheckBoxen selber zeichnen.

Das Zeichnen selbst sollte kein großes Problem sein:
Delphi-Quellcode:
var
  DispRect : TRect;
begin
  DispRect := Item.DisplayRect(drIcon);

  with Sender as TListView do
    if Item.Checked then
      ImageList2.Draw(Canvas, DispRect.Left - 16, DispRect.Top, 1)
    else
      ImageList2.Draw(Canvas, DispRect.Left - 16, DispRect.Top, 0);
end;
In ImageList2 sind zwei 16x16 große Bitmaps mit, die für CheckBox An/Aus stehen. Den Rest, wie auch Checkbox Klick, muss man noch machen. Ist aber alles machbar.

d7user1 24. Mär 2014 18:02

AW: VirtualStringTree - Nodes hinzufügen
 
ich würde schon gerne weiter die listview benutzen. aber das mit dem bitmap zeichnen usw, ich habe es gerade ausprobiert, das ist mir ein wenig zu wackelig.

es gäbe sogar noch einen grund bei der listview zu bleiben:
wenn mein VirtualTreeView nicht genug nodes hat um dem scrollbalken anzuzeigen, dann bekommen meine nodes keine hintergdunfarbe (Brush).

ein manuelles VST.Refresh zeigt mir die farben an. aber ich habe keine ahnung wo ich diesen refresh hinsetzen muss.

edit: ich habe jetzt mal in GetImageIndex ein VST.Invalidate; gesetzt. das scheint zu funktionieren aber ob es schön ist weiß ich nicht.
damit es nicht ständig aufgerufen wird und somit prozessorzeit unnötig für nichts beansprucht wird eine boolsche variable gesetzt wenn es aufgerufen wurde.

Popov 24. Mär 2014 20:35

AW: VirtualStringTree - Nodes hinzufügen
 
Also bisher habe ich noch nicht mit Virtual ListView gearbeitet, ist im Grunde aber eine feine Sache, man muss nur die Daten auslagern. Das mit den Checkboxen ist Pech, da muss man eben selbst programmieren.

NextGrid und VST sehen verdammt gut aus, müssen aber installiert werden.

Vorausgesetzt also Virtual ListView ist nichts, auch NextGrid und VST nicht, eben aus den genannten Gründen, stellt sich die Frage nach dem Beispiel im Beitrag #17. Das ist kein Virtual ListView, arbeitet aber insoweit ähnlich, als das es zuerst komplett leer ist und erst beim Scrollen gefüllt wird. Es ist etwas langsamer, hat dafür aber CheckBoxen, da es eine normale ListView ist. Sollte also die Lösung für dein Problem sein.

d7user1 24. Mär 2014 21:56

AW: VirtualStringTree - Nodes hinzufügen
 
ich werde mir dein beispiel mal ansehen und mit meinem VST vergleichen.

meine "Dateien-lesen-funktion" braucht momentan für das lesen von C:\Windows rekursiv 6 sekunden. (95000 dateien)
die grafische darstellung dauert nur wenige millisekunden.

Popov 24. Mär 2014 22:06

AW: VirtualStringTree - Nodes hinzufügen
 
Nun, da ist nichts besonderes dran, bis auf, dass zuerst nur leere Items angelegt werden. Diese werden später JustInTime gefüllt.

d7user1 24. Mär 2014 22:12

AW: VirtualStringTree - Nodes hinzufügen
 
demnach sind 6 sekunden für ein verzeichnis wie C:\windows normal?

Popov 24. Mär 2014 22:36

AW: VirtualStringTree - Nodes hinzufügen
 
Also ich weiß nicht wie du auf die 6 Sekunden kommst. Ich hab gerade den Code geändert und ihn auch Unterverzeichnisse einbinden lassen. Dauer bei knapp 12000 Dateien im Windowsordner etwa 500 ms (komplett, einlesen und in LV ausgeben).

d7user1 24. Mär 2014 22:52

AW: VirtualStringTree - Nodes hinzufügen
 
mist. ich probiere gleich mal die funktion hier aus der code-lib aus wenn ich die noch finde.

edit:
ok also selbst mit dieser funktion dauert es 4 bis 5 sekunden:
http://www.delphipraxis.net/332578-post.html#392510

kann es sein dass du eine SSD hast?

Popov 24. Mär 2014 23:00

AW: VirtualStringTree - Nodes hinzufügen
 
Delphi-Quellcode:
procedure GetFilesOL(SearchPath: String; ObjectList: TObjectList; SubFolder: Boolean);
var
  SearchRec: TSearchRec;
  FileInfo: TFileInfoEx2;
begin
  SearchPath := IncludeTrailingPathDelimiter(SearchPath);

  if FindFirst(SearchPath + '*.*', faAnyFile or faDirectory, SearchRec) = 0 then
  try
    repeat
      if (SearchRec.Name <> '.') and (SearchRec.Name <> '..') then
        with ObjectList do
        begin
          FileInfo := TFileInfoEx2.Create;
          Add(FileInfo);

          FileInfo.Path := SearchPath;
          FileInfo.Name := SearchRec.Name;
          FileInfo.SearchRec := SearchRec;
        end;
    until FindNext(SearchRec) <> 0;
  finally
    FindClose(SearchRec);
  end;

  //----------------------------------------------------------------------------

  if SubFolder then
  begin
    if FindFirst(SearchPath + '*.*', faDirectory, SearchRec) = 0 then
    try
      repeat
        if ((SearchRec.Attr and faDirectory) = faDirectory) and
          (SearchRec.Name <> '.') and (SearchRec.Name <> '..') then
          GetFilesOL(SearchPath + SearchRec.Name, ObjectList, SubFolder);
      until FindNext(SearchRec) <> 0;
    finally
      FindClose(SearchRec);
    end;
  end;
end;

d7user1 24. Mär 2014 23:04

AW: VirtualStringTree - Nodes hinzufügen
 
jop. also mit deiner prozedur mit stringlist anstatt objektlist dauert es dennoch 4 sekunden.
entweder ist es die stringlist oder es ist weil ich keine ssd habe.

es ist zudem eine angepasste version der datensammlung mit dingen die ich benötige. das würden die 2sekunden überlänge erklären

Popov 24. Mär 2014 23:12

AW: VirtualStringTree - Nodes hinzufügen
 
Liste der Anhänge anzeigen (Anzahl: 1)
Vielleicht hast du einfach nur einen langsamen Rechner.

Teste das mal: (siehe Anhang)

PS: die Sortierung ist noch nicht angepasst und sortiert nur nach Daten, ohne Pfade zu berücksichtigen.

d7user1 24. Mär 2014 23:13

AW: VirtualStringTree - Nodes hinzufügen
 
mh. intel core i7 mit 4* 1.6ghz
ram weiß ich grade nicht aber der ist schon schnell. 1333mhz glaube ich pro block
und eine hybridfestplatte.

dein beispiel läuft bei mir in 7-8 5-6 sekunden durch.

ich hatte mal beobachtet dass mein rechner langsmer wird wenn man ZU OFT ohne einen neustart mit delphi kompiliert.
vielleicht ist es das.

Popov 24. Mär 2014 23:18

AW: VirtualStringTree - Nodes hinzufügen
 
Alter AMD Athlon 7750 Dual-Core Prozessor, 2.70 GHz, und trotzdem schneller :P

EDIT:

Damit du siehst, dass die 500 ms stimmen: http://www.directupload.net/file/d/3...6cqkxl_gif.htm

Wenn du wirklich 5 Sekunden bei gleichem Code brauchst, dann stimmt da was nicht. Teste mal den Speed deiner Festplatte damit: http://www.heise.de/download/hd-tune.html

d7user1 24. Mär 2014 23:34

AW: VirtualStringTree - Nodes hinzufügen
 
selbst nach einem neustart keine wirkliche besserung. mein beispiel lief vorher in 6.X sekunden durch nun in 5.X.
vielleicht ist meine windows-installation hinüber?
dass ich das mit einer testversion von XE2 kompiliere ändert nichts oder?

d7user1 24. Mär 2014 23:58

AW: VirtualStringTree - Nodes hinzufügen
 
Liste der Anhänge anzeigen (Anzahl: 1)
das sieht dann so aus:
http://www.directupload.net/file/d/3...xhpdkb_png.htm
oder so:
http://www.directupload.net/file/d/3...e2ol7r_png.htm

wielange braucht mein berispiel denn bei dir? (anhang)

Popov 25. Mär 2014 00:22

AW: VirtualStringTree - Nodes hinzufügen
 
Sieht ok aus, obwohl 1GB etwas wenig sind. Wiederhole das für dich mal mit 40 GB.

Ich weiß zurzeit auch nicht wo das Problem liegt.

d7user1 25. Mär 2014 00:42

AW: VirtualStringTree - Nodes hinzufügen
 
kann es sein dass das daran liegt dass es ein laptop ist?
könntest du mein beispiel oben eventuell testen?


edit:
ich habe mal die dateiliste der dateien die rekursiv in C:\Windows sind in eine textdatei gepackt.
mein testprogramm lädt nun diese testdatei anstatt die liste selber zusammenzustellen per FindFirst usw usw.

mit dem code aus der code-lib braucht mein rechner 4 bis 5 sekunden. mein angepasster, für meine bedürfnisse, code braucht etwa 5.5 bis 6 sekunden.

und das laden der textdatei direkt in die stringlist benötigt nur 200ms ungefähr. demnach ist es eindeutig meine festplatte die entweder hinüber ist oder
meine windows-installation. das seltsame ist aber dass ein anderer datenträger bei 13000 dateien dennoch 3 sekunden benötigt. ich glaube also es ist die windows-installation.


Alle Zeitangaben in WEZ +1. Es ist jetzt 03:48 Uhr.
Seite 1 von 2  1 2      

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