Jim Knopf hat geschrieben: Do 12. Aug 2021, 14:32
Warum hier mit einem eigenen Record, der die Spalten abbildet, gearbeitet werden muss, verstehe ich einfach nicht - ist doch auch eine Redundanz, die schnell ins Aug gehen kann, sobald man was ändert an den Spalten. Irgendwo müssen die Daten ja immer vorghehalten werden, warum nicht in einer TStrings, auf die man direkt zugreifen kann. Aber es ist eben eine andere Philosophie.
OK, dann hast du das Prinzip von VTV noch nicht verstanden. Vergiss den Record, es ist nur ein Beispiel, weil ich etwas handfestes brauchte, um das Demo-Programm zu machen.
VTV verwaltet die Nodes intern in TVirtualNode Records:
Code: Alles auswählen
type
TVirtualNode = record
Index, // index of node with regard to its parent
ChildCount: Cardinal; // number of child nodes
NodeHeight: Word; // height in pixels
States: TVirtualNodeStates; // states describing various properties of the node (expanded, initialized etc.)
Align: Byte; // line/button alignment
CheckState: TCheckState; // indicates the current check state (e.g. checked, pressed etc.)
CheckType: TCheckType; // indicates which check type shall be used for this node
Dummy: Byte; // dummy value to fill DWORD boundary
TotalCount, // sum of this node, all of its child nodes and their child nodes etc.
TotalHeight: Cardinal; // height in pixels this node covers on screen including the height of all of its
// children
// Note: Some copy routines require that all pointers (as well as the data area) in a node are
// located at the end of the node! Hence if you want to add new member fields (except pointers to internal
// data) then put them before field Parent.
Parent, // reference to the node's parent (for the root this contains the treeview)
PrevSibling, // link to the node's previous sibling or nil if it is the first node
NextSibling, // link to the node's next sibling or nil if it is the last node
FirstChild, // link to the node's first child...
LastChild: PVirtualNode; // link to the node's last child...
Data: record end; // this is a placeholder, each node gets extra data determined by NodeDataSize
end;
Da steht drin, welche Nodes als Geschwister vorhanden sind, welcher Node das erste bzw. letzte Kind in der nächsten Hierarchieebene ist, ob der Node gecheckt ist, usw, usw.
Ganz am Ende steht das Feld "Data", das ist der Platz für die mit dem Node verbundenen Daten, wobei hierfür kein Datentyp festgelegt ist. Die Daten kann man z.B. so wie in meinem Beispiel als Record anbieten, oder aber auch über einen Pointer, der auf irgendwelche Strukturen zeigt, z.B. auch Datenobjekte in deiner eigentlichen Anwendung. Das ist absolut flexibel. Das einzig wichtige ist, dass du dem VTV sagst, wie groß das Feld Data ist - das geschieht mit dem Property NodeDataSize oder über das Ereignis OnGetNodeDataSize. Mit dieser Information reserviert der VTV dann für jeden Node die Größe des TVirtualNode plus die Größe des Datenbereichs (NodeDatasize). Wenn die Daten als Record vorliegen, wäre NodedataSize = SizeOf(...daten-record...). Wenn die Daten eine Instanz einer Klasse sind, wäre NodeDataSize = SizeOf(TDeineDatenKlasse) (oder einfacher SizeOf(TObject) oder SizeOf(Pointer)). Alles andere geschieht dann über die Events: Wenn z.B VTV einen Text in eine Zelle malen soll, wird das Ereignis OnGetCellText aufgerufen (mit Parameter Node und Spalte), und du lässt dir durch VTV.GetNodeData den Pointer zurückliefern, der auf deine Daten zeigt, und letztendlich entscheidet dann dein Eventhandler, wie der anzuzeigende Text in der betreffenden Spalte aus deinen Daten extrahiert wird.
Natürlich kannst du dir von TVirtualStringTree eine neue Klasse ableiten, in der schon vorgegeben ist, wie man die Zelltexte erhält, und damit könntest du via "Node.Strings[ColumnIndex]" auf den anzuzeigenden Text zugreifen.
Jim Knopf hat geschrieben: Do 12. Aug 2021, 14:32
Über CustomDrawCell kann man seine Zellen individuell zusammenmalen wie man es braucht (entspricht wohl dem TreeDrawText):
Code: Alles auswählen
procedure TfMain.tlCustomDrawCell(Sender: TObject; ACanvas: TCanvas;
ARect: TRect; ANode: TdxTreeListNode; AColumn: TdxTreeListColumn;
ASelected, AFocused, ANewItemRow: Boolean; var AText: String;
var AColor: TColor; AFont: TFont; var AAlignment: TAlignment;
var ADone: Boolean);
Heißt das, dass all die Icons in deinem Screenshot erst im CustomDrawCell angezeigt werden? Das macht die Umstellung viel einfacher, weil man im Node-Record dann keine Unmengen von ImageIndices und Formatierungsvorgaben (Bild links oder Bild rechts) vorhalten muss. VTV kann das dann nämlich alles schon.