AGB  ·  Datenschutz  ·  Impressum  







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

VirtualTreeView und icons

Ein Thema von Wishmaster · begonnen am 9. Aug 2014 · letzter Beitrag vom 28. Aug 2014
Antwort Antwort
Wishmaster

Registriert seit: 14. Sep 2002
Ort: Steinbach, MB, Canada
301 Beiträge
 
Delphi XE2 Architect
 
#1

AW: VirtualTreeView und icons

  Alt 10. Aug 2014, 01:19
OK! ich habe es geschaft (Nach dem Red Bull ) so ich hatte recht mit der idee die icon direkt in den NodeRecord zu schreiben!
so jetzt ist der limit nur der arbeitsschpeicher.

so this is my solution! Have fun with it.

Delphi-Quellcode:
type
  PRNodeData = ^TRNodeData;
  TRNodeData = record
   ID : Int64; // pointer
   Title : Widestring;
   Value : Widestring;
   Hiden : Boolean;
   Image : TBitmap; // icon
  end;

procedure TMain_form.RecordTreeBeforeCellPaint(Sender: TBaseVirtualTree;
  TargetCanvas: TCanvas; Node: PVirtualNode; Column: TColumnIndex;
  CellPaintMode: TVTCellPaintMode; CellRect: TRect; var ContentRect: TRect);
var
 Data : PNodeData;
 R : TRect;
begin
  if Assigned(Node)then
   begin
     Data:= FolderTree.GetNodeData(Node);
    if Data^.Colored then
     begin
      case Column of
       0 :
        begin
         TargetCanvas.Brush.Color := $00FFFAF4;
         TargetCanvas.FillRect(CellRect);

        // Draw Icon Test

         R.Left:= ContentRect.Left-16;
         R.Top:= ContentRect.Top -1;
         R.Right:= ContentRect.Bottom + R.Left;
         R.Bottom:= ContentRect.Bottom -1;

         //TargetCanvas.Brush.Color:= clred;
         TargetCanvas.FillRect(R);

         TargetCanvas.Draw(R.Left, 0, Data^.Image); // Icon

        end;
       1 :
        begin
         (* Draw Gradient *)
         GradientFillHorizontal(TargetCanvas, CellRect, $00FFFAF4, clWhite, 100)
        end;
       2 :
        begin
         // comment todo
        end;
      end;


     end;
   end;
end;
ganz vergessen zu sagen, ich benutze eine leere TImageList um den text nach rechts zu bewegen




in meinem test lade ich die icons direkt von der festplatte
später wird das direkt von der DB/Stream geladen!

Delphi-Quellcode:
 Data:= RecordTree.GetNodeData(Parent);
 ...
 Data^.Image:= TBitmap.Create;
 Data^.Image.LoadFromFile('c:\...\...\folder_open.bmp');
 Data^.Image.Transparent := True;
 Data^.Image.TransparentMode := tmAuto;
nochmal danke an alle.

Geändert von Wishmaster (10. Aug 2014 um 01:37 Uhr)
  Mit Zitat antworten Zitat
Wishmaster

Registriert seit: 14. Sep 2002
Ort: Steinbach, MB, Canada
301 Beiträge
 
Delphi XE2 Architect
 
#2

AW: VirtualTreeView und icons

  Alt 10. Aug 2014, 02:27
@Perlsau

normalerweise würde ich dir zustimmen. in meinem fall ist es ein wenig anders,
bei meinem Programm erstellt der benutzer die DB/File und die felder Dynamisch.
so was ist wenn der benutzer 20000 einträge hat? und in jedem eintrag einen anders icon haben will.
wenn ich die Icons vorab in die TImageList Lade und nur den index in die DB speicher,
kann es später zum problem werden. sagen wir mal ich muss ein icon löschen/ändern (aus rechtlichen grunden,...)
so beim nächsten programm update stimmen die icons nicht mit dem eintrag überein
da der index zu den icon sich geändert hat. oder man macht die DB/Datei komplett mit einem anderen Programm auf.

ein anderer fall, was ist wenn du den folder mit deinen icons in die Virtual TreeView einlesen wilst
zum beispiel ich habe 1,148,532 icons auf meinem Computer das sind ~10 GB
ich glaube da versagen die meisten listen.

Datenbankgröße 32 TB (auch durch Dateisystem und Betriebssystem begrenzt)

und ich glaube der speed unterschied ist nicht so groß.



thx.
  Mit Zitat antworten Zitat
Perlsau
(Gast)

n/a Beiträge
 
#3

AW: VirtualTreeView und icons

  Alt 10. Aug 2014, 08:46
Daß in deinem Fall die Kapazität der TImageList nicht ausreicht, ist nachvollziehbar. Dennoch würde ich im NodeDataRecord nicht das eigentliche Bitmap speichern, sondern eine Id auf eine Liste bzw. auf die entsprechenden der DB-Bildtabelle. Ob du jetzt im Node selbst das Icon austauschst oder in der Liste macht im Grunde keinen Unterschied – abgesehen davon, daß nicht bei jedem Zugriff auf den Data-Record das Bitmap aus dem Speicher gekramt werden muß, denn das wird ja nur einmal beim Aufbau des Baums benötigt.

Das mit der Geschwindigkeit hab ich jetzt nicht mit einem TreeView ausprobiert, aber mit Datenbanken. Wenn ich z.B. eine Tabelle, die zwei Blob-Felder (ein Bitmap und ein RTF-Text) beinhaltet, sortiere, ist das ohne diese beiden Blob-Felder entsprechend schneller: Je mehr Datensätze in der Tabelle, desto größer der Geschwindigkeitsvorteil. Die benötigten Felder lasse ich dann aus einer zweiten Tabelle nach Bedarf selektieren (z.B. im AfterScroll-Ereignis). Mit anderen Worten: Da ich die beiden Blob-Felder nur zur Anzeige, nicht aber zur Anwendung von Such- und Sortierkriterien benötige, muß ich die nicht mitschleppen. Aus diesem Grund gibt es bei vielen Komponenten wie z.B. auch beim VTV die beiden Schalter BeginUpdate und EndUpdate.

Meine Bilder im dargestellten VTV kommen ebenfalls aus einer Datenbank und sind zudem ziemlich groß. Beim Baumaufbau werden diese Bitmaps, die an anderer Stelle in Originalgröße benötigt werden, mit StretchDraw in die Bitmaps der TImageList kopiert, wonach letztere dann dem VTV zugewiesen wird.
  Mit Zitat antworten Zitat
Aviator

Registriert seit: 3. Jun 2010
1.611 Beiträge
 
Delphi 10.3 Rio
 
#4

AW: VirtualTreeView und icons

  Alt 10. Aug 2014, 12:25
Dennoch würde ich im NodeDataRecord nicht das eigentliche Bitmap speichern, sondern eine Id auf eine Liste bzw. auf die entsprechenden der DB-Bildtabelle.
Da ich auch sehr viel mit Images und dem VTV arbeite, würde ich es ebenfalls so machen wenn mir eine ImageList nicht ausreichen würde. Der Vorteil ist nicht nur der Speicher, der pro Bild nur einmal belegt wird und nicht mehrfach pro Node, sondern sobald du die Liste mit den Bilder aktualisierst bzw. ein Bild austauschst, musst du nur den VTV mit VTV.Invalidate bzw. VTV.InvalidateNode(ANode) neu zeichnen lassen und die Bilder sind direkt auf dem neuen Stand.

Zitat von Wishmaster:
ganz vergessen zu sagen, ich benutze eine leere TImageList um den text nach rechts zu bewegen
Diesen Umweg würde ich nicht gehen, sondern ich würde im PainText Event des VTV den Text manuell um die Breite des betreffenden Images bewegen. Die Breite wird wohl immer gleich sein bzw. die könntest du auch dann aus der entsprechenden Liste auslesen. Für die Liste würde sich vielleicht dann schon eine eigene Klasse anbieten, in der noch zusätzliche Informationen zum Bild abgelegt werden können wie eben z.B. die Breite und die Höhe des Bildes.

Dann kannst du ganz einfach im PaintText Event per Index auf die Liste der Bilder zugreifen und dann um die Breite des Bildes verschieben.

Das mal so aus meiner Sicht. Vielleicht hilft es dir ja weiter.
  Mit Zitat antworten Zitat
Wishmaster

Registriert seit: 14. Sep 2002
Ort: Steinbach, MB, Canada
301 Beiträge
 
Delphi XE2 Architect
 
#5

AW: VirtualTreeView und icons

  Alt 12. Aug 2014, 01:49
ok nochmal ich habe eine DB, und jeder eintrag in der DB hat sein eigenes Icon das ich dann nach bedarf in der VTV anzeigen möchtebei.
so jetzt muss ich das icon doch irgendwie aus der DB rausholen damit ich das anzeigen kann. richtig?
so ob ich das in eine NodeRecord, ImageList oder in irgend einer anderen liste zwischenspeicher und dan per index daraf zugreife.
(und wie schon gesagt eine ImageList kommt nicht in fragen wegen limit)
der speicher (Ram) wird immer gleich ausgelastet! richtig? und ein icon wiegt ~800 bytes.
ehrlich gesagt ich sehe kein unterschied. abgesehen von ein wenig mehr arbeitsspeicher verbrauch.


aber ich möchte es richtig machen, und ich würde mich echt freuen wenn ihr mir eine kleine demo schreiben konntet.
es gibt bestimmt jemanden der mehr plan von db's un vtv's hat den ich. und zeit um mir ne demo zu schreiben.
ich freue mich über jede hilfe. So thanks in advance


by the way ich benutze die Absolute Database
  Mit Zitat antworten Zitat
Perlsau
(Gast)

n/a Beiträge
 
#6

AW: VirtualTreeView und icons

  Alt 12. Aug 2014, 02:44
Selbstverständlich mußt du das Icon erst mal aus der Datenbank einlesen. Mit deiner Methode, das Icon in NodeData zu speichern, verursachst du unnötige CPU-Last beim Handling mit dem VTV, was natürlich bedeutet, daß der Aufbau eines riesigen Trees wie in deinem Fall unnötig verzögert wird. So müssen z.B. die Bitmaps in NodeData beim Umsortieren ständig mitkopiert werden, was bei einer externen Liste (Generics TObjectList) nicht nötig wäre, denn die hättest du einfach nur nach dem Index sortiert, damit das gesuchte Bitmap schnell gefunden wird.

Dazu erzeugst du dir erstmal eine Klasse:
Delphi-Quellcode:
UNIT Startbilder;

INTERFACE

USES
  ExtCtrls, StdCtrls, Classes, Graphics;

TYPE
  TStartBild = Class

    PRIVATE { Private-Deklarationen }
      Var
        fBild : TImage;
        fIndex : Integer;
        
      Function GetfBild : TImage;
      Procedure SetfBild(Const Value : TImage);
      Function GetfIndex : TImage;
      Procedure SetfIndex(Const Value : TImage);

    PUBLIC { Public-Deklarationen  }

      Constructor Create();
      Destructor Destroy; override;

      Property Bild : TImage read GetfBild write SetfBild;
      Property Index : Integer read GetfIndex write SetfIndex;

  END;

IMPLEMENTATION
{ TStartBild }

Function TStartBild.GetfBild: TImage;
begin
  Result := fBild;
end;

Procedure TStartBild.SetfBild(Const Value: TImage);
begin
  fBild.Assign(Value);
end;

Function TStartBild.GetfIndex: Integer;
begin
  Result := fBild;
end;

Procedure TStartBild.SetfIndex(Const Value: Integer);
begin
  fBild.Assign(Value);
end;

Constructor TStartBild.Create;
begin
  inherited;
  fBild := TImage.Create(nil);
  fBild.Visible := False;
  fBild.AutoSize := False;
  fBild.Stretch := False;
  fBild.Proportional := False;
  fBild.Center := False;
  fBild.Width := 30; // oder wie die Größe deiner Icons eben ist
  fBild.Height := 30;
end;

Destructor TStartBild.Destroy;
begin
     fBild.Free;
  inherited;
end;

end.
Dann deklariest du in der Formular-Unit, die den VTV aufnehmen soll, eine Objektliste:
Delphi-Quellcode:
  ...
  PRIVATE { Private-Deklarationen }
    Var
      BList : Generics.Collections.TObjectList<TStartBild>;
  ...
In FormCreate und FormDestroy deines VTV-Formulars schreibst du:
Delphi-Quellcode:
Procedure TFormMain.FormCreate(Sender: TObject);
begin
  BList := TObjectList<TStartBild>.Create;
  ...
end;

Procedure TFormMain.FormDestroy(Sender: TObject);
begin
  If BList.Count > 0 Then
  BList.DeleteRange(0,BList.Count-1);
  BList.Free;
  ...
end;
Den VTV baust du in einer privaten Methode auf, die z.B. bei Programmstart aufgerufen wird. Dort gehst du deine DB-Tabelle durch und liest die entsprechenden Spalten aus. In NodeData.Index schreibst du den Index deiner Tabelle, der mit dem Index in BList korrespondiert (nicht der Listen-Index, sondern der Eintrag Index, der in der Klasse festgelegt wurde).

Nachtrag:

Probier's doch einfach mal aus: Erstelle eine Exe mit den Icons in NodeData und eine mit den Icons in einer Objektliste, wobei du jedesmal die Zeit mißt, die vergeht, wenn du
  • den Baum aufbaust
  • den Baum sortierst
  • im Baum suchst.

Geändert von Perlsau (12. Aug 2014 um 03:03 Uhr) Grund: Nachtrag
  Mit Zitat antworten Zitat
Dejan Vu
(Gast)

n/a Beiträge
 
#7

AW: VirtualTreeView und icons

  Alt 12. Aug 2014, 07:22
[QUOTE=Perlsau;1268418]Mit deiner Methode, das Icon in NodeData zu speichern, verursachst du unnötige CPU-Last beim Handling mit dem VTV, was natürlich bedeutet, daß der Aufbau eines riesigen Trees wie in deinem Fall unnötig verzögert wird. So müssen z.B. die Bitmaps in NodeData beim Umsortieren ständig mitkopiert werden,...[QUOTE] Der Speicherverbrauch wächst minimal, d.h. um 4 Byte pro Record. Deine Argumention ist daher nicht schlüssig. Einzig die eventuell redundante Instantiierung von identischen Icons könnte man verbessern. Hier würde ich einen einfachen Cache vorschlagen. Zu klären wäre nur eine Funktion, die zu einem Icon einen eindeutigen Schlüssel generiert.

Zitat:
Den VTV baust du in einer privaten Methode auf, die z.B. bei Programmstart aufgerufen wird. Dort gehst du deine DB-Tabelle durch und liest die entsprechenden Spalten aus.
Das verzögert den Programmstart unnötig. Wenn nämlich nicht alle Icons benötigt werden, d.h. vielleicht auch nicht sichtbar sind. Ein Cache macht prinzipiell das Gleiche, nur eben on demand, bzw. per lazy load.
Diese Implementierung ist somit skalierbar, d.h. sie funktioniert auch bei sehr großen Datenmengen. Hier wäre natürlich die Visualisierung anzupassen, d.h. nur die Daten zu laden und im Speicher zu halten, die gerade benötigt werden.
  Mit Zitat antworten Zitat
Antwort Antwort


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 07:21 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-2025 by Thomas Breitkreuz