![]() |
Fragen zu VirtualTreeView
Moin,
ich arbeite das Tutorial zu Virtualtreeview durch und habe schon auf den ersten Seiten zwei Fragen: 1) auf Seite zwei wird geschrieben wie man an einer bestimmten Stelle einen Node einfügen kann:
Delphi-Quellcode:
allerdings wird bei mir das "amInsertAfter" als unbekannt markiert - fehlt mir da ein uses ?
Node := vst.InsertNode(vst.FocusedNode, amInsertAfter);
2) auf Seite 3 werden Noites mit Beschriftung erstellt:
Delphi-Quellcode:
Ich hötte erwartet das jetzt statt "Node" immer "Node-Nummer 1..2..3..4..usw" steht - es steht aber weiterhin nur Node.
function AddVSTStructure(AVST: TCustomVirtualStringTree; ANode: PVirtualNode;
ARecord: TTreeData): PVirtualNode; var Data: PTreeData; begin Result:=AVST.AddChild(ANode); Data:=AVST.GetNodeData(Result); Avst.ValidateNode(Result, False); Data^.FCaption:=ARecord.FCaption; end; procedure TForm1.Button3Click(Sender: TObject); var I: Integer; TreeData: TTreeData; begin VST.NodeDataSize:=SizeOf(TTreeData); VST.BeginUpdate; for I:=0 to 100 do begin TreeData.FCaption:='Node-Nummer: '+IntToStr(I); AddVSTStructure(VST,nil,TreeData); end; VST.EndUpdate; end; Denke ich da falsch ? Was mache ich denn wenn da nicht nur Node stehen soll.´?? Hans |
AW: Fragen zu VirtualTreeView
amInsertAfter war in der Unit VirtualTrees.pas.
Mit Version 7.6, die du scheinbar nutzt, gab es Breaking Changes. Deswegen ist amInsertAfter jetzt in VirtualTrees.Types.pas. |
AW: Fragen zu VirtualTreeView
Zitat:
|
AW: Fragen zu VirtualTreeView
Zitat:
Zitat:
Hans |
AW: Fragen zu VirtualTreeView
Zitat:
|
AW: Fragen zu VirtualTreeView
Zitat:
Speichere deine Daten in einer ObjectList oder sowas Klassenstruktur. Damit lässt es sich wesentlich besser arbeiten. Das ist anfänglich mehr Aufwand, aber es lohnt sich. |
AW: Fragen zu VirtualTreeView
Zitat:
![]() Bis bald... Thomas |
AW: Fragen zu VirtualTreeView
Zitat:
|
AW: Fragen zu VirtualTreeView
Leider habe ich noch eine Frage da ich etwas noch nicht verstehe - geht um das Speichern der Daten. Ich habe noch nie mit Streams gearbeitet, deswegen stehe ich da ein bisschen auf dem Schlauch.
Zum Speichern wird folgende procedure genutzt:
Delphi-Quellcode:
Da sind die Daten aber nur ein String, wie geht das denn wenn es mehrere Strings sind ? So etwa ? Das kommt mir kompliziert vor:
procedure TForm1.vstSaveNode(Sender: TBaseVirtualTree; Node: PVirtualNode;
Stream: TStream); var Data: PTreeData; Len: integer; begin Data := vst.GetNodeData(Node); Len := Length(Data.TestStr); Stream.write(Len, SizeOf(Len)); Stream.write(PChar(Data.TestStr)^, Len); end;
Delphi-Quellcode:
Wie ist das denn richtig ?
procedure TSerienDB.VSTSaveNode(Sender: TBaseVirtualTree; Node: PVirtualNode; Stream: TStream);
var Data: PTreeData; Len: integer; begin Data := VST.GetNodeData(Node); Len := Length(Data.FCaption); Stream.write(Len, SizeOf(Len)); Stream.write(PChar(Data.FCaption)^, Len); Len := Length(Data.FColumn1); Stream.write(Len, SizeOf(Len)); Stream.write(PChar(Data.FColumn1)^, Len); Len := Length(Data.FColumn2); Stream.write(Len, SizeOf(Len)); Stream.write(PChar(Data.FColumn2)^, Len); Len := Length(Data.FColumn3); Stream.write(Len, SizeOf(Len)); Stream.write(PChar(Data.FColumn3)^, Len); end; Gruss Hans |
AW: Fragen zu VirtualTreeView
Zitat:
Delphi-Quellcode:
Denn PChar = PWideChar
Len := Length(S) * SizeOf(S[1]);
// oder Len := Length(S) * SizeOf(Char); und WideChar = 2 Byte (seit Delphi 2009, also seit 15 Jahren schon) |
AW: Fragen zu VirtualTreeView
Zitat:
Bis bald... Thomas |
AW: Fragen zu VirtualTreeView
Moin
das kann sein, da habe ich einfach den Code aus dem Tutorial kopiert. Was mich irritiert ist das ich jedes Feld aus dem Record separat speichern muss. Kann man da den Record nicht en bloc speichern? Hans |
AW: Fragen zu VirtualTreeView
Hallo Thomas,
mir ging es um die einfachste Methode die Datei zu speichern. Es handelt sich um Fernsehserien, sprich Serie Folge Wie oft abgespielt Das ist relativ statisch, da werden die Daten eben nur selten geändert. Und da suche ich halt den bequemsten Weg. Hans |
AW: Fragen zu VirtualTreeView
Wenn man "Fernsehserien" durch "Alben" ersetzt und "Folgen" durch "Lied", hat man das Grundkonzept von meinem mp3-Player. :stupid:
Da habe mir ich zum Speichern ein eigenes Dateiformat gebastelt, welches auch nicht angepasst werden muss, wenn später mal weitere Informationen gespeichert werden sollen. Zusätzlich zur Länge und den eigentlichen String-Inhalt kommt bei mir u.a. noch eine internere "ID" hinzu, die angibt, welche Art von Info nun als nächstes kommt. Z.B. 1: Name der Serie, 2: Name der Folge, 3: Dateiname der Datei, 4: Größe der Datei, etc.pp. Dann können später weitere Datenfelder hinzugefügt werden, ohne dass ich das Dateiformat ändern muss (zwecks Abwärtskompatibilität beim Update des Programms). Das Ende der Daten für ein Objekt wird bei mir über die ID "255" gekennzeichnet. Gespeichert werden bei mir nur die Informationen zu den einzelnen Titeln (bei dir: Episoden). Die Gruppierung nach Alben (Serien) geschieht bei mir erst zur Laufzeit beim Laden der Liste. Dann ist auch leicht eine alternative Gruppierung im Treeview möglich (nach Erscheinungsjahr, Genre, Dauer, wasweißich). Das, was dir zu kompliziert vorkommt, ist also vermutlich der sinnvollere Weg. "Problem" sind halt die Strings mit variabler Länge. ;-) Nachteil bei meinem Ansatz ist nur, dass selbst kleinste Änderungen an einem einzelnen Objekt (Abspielzähler +1) ein Neuschreiben der gesamten Speicherdatei benötigen. Ein punktgenaues Ändern einzelner Stellen in der Datei ist nicht vorgesehen. |
AW: Fragen zu VirtualTreeView
Zitat:
Delphi-Quellcode:
Im TreeView Knoten "Data" auf ein TSeriesItem zeigen lassen oder den Daten-Index speichern. JSON als DB-Format. Das Serialisieren mit mORMot ist tolerant. Du kannst jeder Zeit dem Daten-Record TSeriesItem Felder hinzufügen oder sie wieder entfernen.
uses
mormot.core.base, mormot.core.json, mormot.core.os; type TSeriesItem = packed record FileName: String; SeriesName: String; EpisodeName: String; PlaybackCount: Integer; end; TSeriesItems = array of TSeriesItem; TSeriesDB = record Items: TSeriesItems; function Load(const pmcFileName: String): Boolean; procedure Save(const pmcFileName: String); end; function TSeriesDB.Load(const pmcFileName: String): Boolean; var json: RawJson; begin Result := False; json := StringFromFile(pmcFileName); if json <> '' then Result := (DynArrayLoadJson(Items, Pointer(json), TypeInfo(TSeriesItems)) <> Nil); end; procedure TSeriesDB.Save(const pmcFileName: String); var json: RawJson; begin json := DynArraySaveJson(Items, TypeInfo(TSeriesItems)); if json <> '' then FileFromString(json, pmcFileName); end; Oder klassisch mit Hilfe von TDynArray umgesetzt:
Delphi-Quellcode:
Anwendung so:
type
TSeriesDB = class(TObject) private FList: TDynArray; FItems: TSeriesItems; FItemCount: Integer; function GetItem(pmIndex: Integer): PSeriesItem; public constructor Create; destructor Destroy; override; function Add(const pmcFileName: String; const pmcSeriesName, pmcEpisodeName: String; pmPlaybackCount: Integer = 0): Integer; function Delete(pmIndex: Integer): Boolean; function LoadFromJsonFile(const pmcFileName: String): Boolean; function SaveToJsonFile(const pmcFileName: String): Boolean; property Item[pmIndex: Integer]: PSeriesItem read GetItem; property ItemCount: Integer read FItemCount; end; constructor TSeriesDB.Create; begin inherited Create; FList.Init(TypeInfo(TSeriesItems), FItems, @FItemCount); end; destructor TSeriesDB.Destroy; begin FList.Clear; inherited Destroy; end; function TSeriesDB.GetItem(pmIndex: Integer): PSeriesItem; begin if (pmIndex >= 0) and (pmIndex < FItemCount) then begin Result := @FItems[pmIndex]; end else Result := Nil; end; function TSeriesDB.Add(const pmcFileName, pmcSeriesName, pmcEpisodeName: String; pmPlaybackCount: Integer): Integer; var item: PSeriesItem; begin item := FList.NewPtr; item.FileName := pmcFileName; item.SeriesName := pmcSeriesName; item.EpisodeName := pmcEpisodeName; item.PlaybackCount := pmPlaybackCount; Result := FItemCount - 1; end; function TSeriesDB.Delete(pmIndex: Integer): Boolean; begin Result := FList.Delete(pmIndex); end; function TSeriesDB.LoadFromJsonFile(const pmcFileName: String): Boolean; var json: RawJson; begin json := StringFromFile(pmcFileName); if json <> '' then Result := (FList.LoadFromJson(Pointer(json), Nil, Nil, True) <> Nil) else Result := False; end; function TSeriesDB.SaveToJsonFile(const pmcFileName: String): Boolean; var json: RawJson; begin json := FList.SaveToJson(True, jsonHumanReadable); if json <> '' then Result := FileFromString(json, pmcFileName) else Result := False; end;
Delphi-Quellcode:
Bei Verwendung als Grid ohne filternde Funktionen reicht der Zugriff über Node Index auf die Daten aus.
procedure ...DoGetText(Sender: TBaseVirtualTree; Node: PVirtualNode; Column: TColumnIndex; TextType: TVSTTextType; var CellText: string);
var item: PSeriesItem; begin item := FSeriesDB.Item[Node.Index]; if item <> Nil then begin case Column of 0: CellText := item.FileName; 1: CellText := item.SeriesName; 2: CellText := item.EpisodeName; 3: Celltext := item.PlaybackCount.ToString; end; end; end; begin FSeriesDB := TSeriesDB.Create; FSeriesDB.Add('X.mp4', 'X-Men', 'Folge 2'); FSeriesDB.Add('Y.mp4', 'Akte-Y', 'Folge 456'); VirtualStringTree.OnGetText := DoGetText; VirtualStringTree.RootNodeCount := FSeriesDB.ItemCount; Bis bald... Thomas |
AW: Fragen zu VirtualTreeView
Zitat:
Speichere deine Daten in einer Klassenstruktur und einer generischen Liste, dann brauchst du keine Streams. |
Alle Zeitangaben in WEZ +1. Es ist jetzt 08:10 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