AGB  ·  Datenschutz  ·  Impressum  







Anmelden
Nützliche Links
Registrieren
Thema durchsuchen
Ansicht
Themen-Optionen

VirtualStringTree - Nodes hinzufügen

Ein Thema von d7user1 · begonnen am 23. Mär 2014 · letzter Beitrag vom 30. Mär 2014
Antwort Antwort
Seite 1 von 2  1 2      
d7user1
(Gast)

n/a Beiträge
 
#1

AW: VirtualStringTree - Nodes hinzufügen

  Alt 23. Mär 2014, 22:47
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.
  Mit Zitat antworten Zitat
Benutzerbild von Sir Rufo
Sir Rufo

Registriert seit: 5. Jan 2005
Ort: Stadthagen
9.454 Beiträge
 
Delphi 10 Seattle Enterprise
 
#2

AW: VirtualStringTree - Nodes hinzufügen

  Alt 23. Mär 2014, 23:29
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.
Kaum macht man's richtig - schon funktioniert's
Zertifikat: Sir Rufo (Fingerprint: ‎ea 0a 4c 14 0d b6 3a a4 c1 c5 b9 dc 90 9d f0 e9 de 13 da 60)

Geändert von Sir Rufo (23. Mär 2014 um 23:40 Uhr)
  Mit Zitat antworten Zitat
Popov
(Gast)

n/a Beiträge
 
#3

AW: VirtualStringTree - Nodes hinzufügen

  Alt 24. Mär 2014, 00:12
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.
  Mit Zitat antworten Zitat
d7user1
(Gast)

n/a Beiträge
 
#4

AW: VirtualStringTree - Nodes hinzufügen

  Alt 24. Mär 2014, 00:13
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).

Geändert von d7user1 (24. Mär 2014 um 00:15 Uhr)
  Mit Zitat antworten Zitat
Popov
(Gast)

n/a Beiträge
 
#5

AW: VirtualStringTree - Nodes hinzufügen

  Alt 24. Mär 2014, 00:21
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.
  Mit Zitat antworten Zitat
d7user1
(Gast)

n/a Beiträge
 
#6

AW: VirtualStringTree - Nodes hinzufügen

  Alt 24. Mär 2014, 00:24
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

Geändert von d7user1 (24. Mär 2014 um 00:53 Uhr)
  Mit Zitat antworten Zitat
d7user1
(Gast)

n/a Beiträge
 
#7

AW: VirtualStringTree - Nodes hinzufügen

  Alt 24. Mär 2014, 02:08
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?

Geändert von d7user1 (24. Mär 2014 um 03:18 Uhr)
  Mit Zitat antworten Zitat
Benutzerbild von jaenicke
jaenicke

Registriert seit: 10. Jun 2003
Ort: Berlin
9.869 Beiträge
 
Delphi 12 Athens
 
#8

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
Popov
(Gast)

n/a Beiträge
 
#9

AW: VirtualStringTree - Nodes hinzufügen

  Alt 24. Mär 2014, 06:56
@ 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.
  Mit Zitat antworten Zitat
nuclearping

Registriert seit: 7. Jun 2008
708 Beiträge
 
Delphi 10.2 Tokyo Professional
 
#10

AW: VirtualStringTree - Nodes hinzufügen

  Alt 24. Mär 2014, 08:14
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.

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 VST.GetFirst ... while ... VST.GetNodeData ... Daten mit Suchparametern vergleichen ... end VST.GetNext , bzw. GetFirstSibling , GetNextSibling , usw. Oder per OnIncrementalSearch -Event und dann mit VST.IterateSubTree.
  Mit Zitat antworten Zitat
Antwort Antwort
Seite 1 von 2  1 2      


Forumregeln

Es ist dir nicht erlaubt, neue Themen zu verfassen.
Es ist dir nicht erlaubt, auf Beiträge zu antworten.
Es ist dir nicht erlaubt, Anhänge hochzuladen.
Es ist dir nicht erlaubt, deine Beiträge zu bearbeiten.

BB-Code ist an.
Smileys sind an.
[IMG] Code ist an.
HTML-Code ist aus.
Trackbacks are an
Pingbacks are an
Refbacks are aus

Gehe zu:

Impressum · AGB · Datenschutz · Nach oben
Alle Zeitangaben in WEZ +1. Es ist jetzt 06:12 Uhr.
Powered by vBulletin® Copyright ©2000 - 2025, Jelsoft Enterprises Ltd.
LinkBacks Enabled by vBSEO © 2011, Crawlability, Inc.
Delphi-PRAXiS (c) 2002 - 2023 by Daniel R. Wolf, 2024 by Thomas Breitkreuz