![]() |
XML-Struktur in Objekte verwalten
Hi,
ich habe ![]() Nun möchte ich diese Struktur gerne objektorientiert umsetzen (mit TObject und TObjectlist). Mein Problem ist hier, dass ich wie bei der TreeView ein TreeNode habe, der unendlich viele Nodes besitzen kann und DER wiederum auch unendlich viele besitzen kann. Wie kann ich das objektorientiert umsetzen, hat jemand eine Idee? |
Re: XML-Struktur in Objekte verwalten
Will noch ein kleines Beispiel nachschieben, damit meine Frage noch deutlicher ist ;-)
Ich habe ein Objekt...
Delphi-Quellcode:
...dennoch möchte ich, dass DIESES Objekt wiederum Objekte vom Typ TOrdner enthalten kann (Ordner können ja Unterordner enthalten und diese wiederum Unterordner usw.).
type
TOrdner = class(TObject) Ordnername : String; Expanded: Boolean; end; Diese ganzen Ordner, möchte ich dann in einem einzelnen Objekt (z.B. TOrdnerSammlung vom Typen TObjectList) ablegen und speichern. So, nun hoffe ich, dass es klarer ist - denke, dass man mit meinem ersten Post nicht soviel anfangen konnte ;-) |
Re: XML-Struktur in Objekte verwalten
Hallo Yheeky,
ich selbst habe auch so ein Problem gehabt (es ging aber um eine Website mit deren Unterseiten) und habe letztendlich jedem Node einfach den Pointer eines erstellten Objektes mitgegeben. Damit hast du die Struktur in einem Baum, aber die Inhalte in den einzelnen Objekten. Sobald du auf einen Node zugreifst, kannst du dann das drangehängte Objekte auslesen. Grüße Jürgen |
Re: XML-Struktur in Objekte verwalten
Hallo Jürgen,
klingt gut, aber verstehe ich leider nicht :-( Kannst du das vielleicht einem Laien nochmal erklären :-) Vielleicht auch mit Code, dann ist´s vielleicht eindeutiger. Danke! |
Re: XML-Struktur in Objekte verwalten
Delphi-Quellcode:
Allerdings sollte das ganze schon ordentlich gekapselt sein (ohne Setter...)
type
TOrdner = class(TObject) Ordnername : String; Expanded: Boolean; Unterordner: TOrdnerSammlung; end; |
Re: XML-Struktur in Objekte verwalten
Ja, sowas in der Art dachte ich auch, allerdings sagt mit Delphi, wenn ich die beiden Klassen (TOrdner und TOrdnerSammlung) in zwei Units auslagere, dass ich "keine Zirkuläre Unit-Referenz" haben darf - und diese brauchte ich ja, weil man sonst die Objekte nicht findet :-(
|
Re: XML-Struktur in Objekte verwalten
Zitat:
![]() Die Klasse TComponent ist übrigens ein Composite. Mit Hilfe des Property ComponentCount und dem Array-Property Components[] kann man ganze Baumstrukturen aufbauen. Das Property Owner ist ebenfalls wichtig, damit jedes Objekt seinen Vorfahren in der Hierarchie kennt. Du kannst dir die Sache am Anfang einfach machen und die Klasse TOrder von TComponent ableiten. Später willst du aber vielleicht von TComponent weggehen, da diese Klasse doch etwas Overhead mit sich rumträgt. |
Re: XML-Struktur in Objekte verwalten
Mit TComponent möchte ich ungern arbeiten. Ich würde gerne meine eigene Klasse entwickeln, weil ich - wie du schon vermutet hast - den ganzen Overhead nicht mit drinhaben möchte.
Ist das so schwer, solch eine Klasse zu entwickeln? |
Re: XML-Struktur in Objekte verwalten
Zitat:
Delphi-Quellcode:
NodeListU:
unit NodeTypeU;
interface type TNodeCustom = class end; implementation end.
Delphi-Quellcode:
NodeU:
unit NodeListU;
interface uses Classes, NodeTypeU; type TNodeList = class private FNodes: TList; public constructor create; destructor destroy; override; procedure Clear; procedure addNode(Node:TNodeCustom); end; implementation { TNodeList } constructor TNodeList.create; begin FNodes:=TList.Create; end; destructor TNodeList.destroy; begin Clear; FNodes.free; inherited; end; procedure TNodeList.Clear; var i:integer; ItemObject:TObject; begin for i:=1 to FNodes.Count do begin ItemObject:=FNodes[i-1]; ItemObject.free; end; FNodes.Clear; end; procedure TNodeList.addNode(Node: TNodeCustom); begin FNodes.Add(Node); end; end.
Delphi-Quellcode:
unit NodeU;
interface uses NodeTypeU, NodeListU; type TNode = class(TNodeCustom) private FChildNodes:TNodeList; public constructor create; destructor destroy; override; procedure addChild(Node:TNode); end; implementation { TNode } constructor TNode.create; begin FChildNodes:=TNodeList.create; end; destructor TNode.destroy; begin FChildNodes.free; inherited; end; procedure TNode.addChild(Node: TNode); begin FChildNodes.addNode(Node); end; end. |
Re: XML-Struktur in Objekte verwalten
Ich habe schon gelesen, dass man das umgehen kann, aber anhand deines Beispieles könnte ich jetzt nicht sehen, was da genau TOrdner und TOrdnerSammlung ist.
Sorry, aber das versteh ich noch nicht :cry: |
Re: XML-Struktur in Objekte verwalten
Guck doch mal in Richtung "Objects", wie beim Stringgrid. Zumindest der VST kann das auch. Verstehe zwar jetzt das konkrete Problem nicht, aber unterbringen kann man da alles.
|
Re: XML-Struktur in Objekte verwalten
Hallo Christian,
ich frage nochmal nach, was genau der Zweck dieses objektorientierten Aufbaus ist. Nehmen wir an, diese Infos soll Dein Objekt halten:
Delphi-Quellcode:
In dem Fall würden ja alleine die Infos im gefüllten TreeView
type
TOrdner = class(TObject) Ordnername : String; Expanded: Boolean; end; aussreichen, d.h. du bräuchtest eigentlich nicht noch Objekte anlegen, sondern könntest bei Bedarf direkt auf den Node des TreeViews zugreifen. Falls das Objekt größer werden soll, hier noch mal eine genauere Beschreibung meiner Umsetzung: Dem TreeView kannst du anstatt nur einer Beschreibung auch eine Beschreibung mit einem Pointer mit auf den Weg geben, also so:
Delphi-Quellcode:
Du könntest also beim Füllen des TreeViews ein Ordner-Objekt
NewTreeNode:= aTreeView.Items.AddChildObject(aParent, 'Nodename', Pointer);
erstellen und dessen Pointer an den Knoten dranhängen, etwa so:
Delphi-Quellcode:
Dabei habe ich das Ordner-Objekt so deklariert:{ Ordner-Objekt erstellen } NewFolder:= TFolder.Create(aXmlNode.Nodes[i].AttributeByName['Name']); { Pointer des Ordner-Objektes dem erstellten Knoten übergeben, sowie den oben bereits übergebenen Ordnernamen } NewTreeNode:= aTreeView.Items.AddChildObject(aParent, NewFolder.Foldername, NewFolder);
Delphi-Quellcode:
type
TFolder = class(TObject) private fFoldername : String; fExpanded: Boolean; public constructor Create(const aFoldername: string); property FolderName: string read fFoldername write fFoldername; end; Ganz wichtig zu sagen ist jedoch, dass der TreeView nicht automatisch auch die Freigabe dieser erstellen Ordner-Objekte durchführt. Löschst du also einen Knoten aus dem Baum, bist du auch für die Freigabe des Ordner-Objektes verantwortlich. Es gibt eine stark erweiterte Tree-Komponente, die sich ![]() nennt (oft auch unter VST hier im Forum zu finden). Dieser ist von Grund auf neu programmiert und besitzt u.a. auch eine automatische Speicherverwaltung der übergebenen Objekte. Nun zum Abrufen des Knotens mit Objekt:
Delphi-Quellcode:
Im obigen Fall würde jetzt beides mal das gleiche angezeigt,{ Normaler Text des Knotens } ShowMessage(TreeView1.Selected.Text); { Über casten mit TFolder kannst du den Pointer des Knotens gezielt ansprechen und die Eigenschaft Foldername abfragen } ShowMessage(TFolder(TreeView1.Selected.Data).FolderName); aber du kannst ja dein Objekt wie gewünscht aufbauen. Grüße Jürgen |
Re: XML-Struktur in Objekte verwalten
Hallo Jürgen,
danke für den Code - hast dir richtig Mühe gegeben! Ich habe deinen Ansatz nun auch verstanden, ABER ;-) Zitat:
Delphi-Quellcode:
Die Dateien müssen ja noch bedacht werden und deswegen glaube ich wäre ein objektorientierter Ansatz nicht schlecht.
type
TOrdner = class(TObject) Ordnername : String; Expanded: Boolean; Unterordner : TOrdner; Dateien : TDatei; end; Im nächsten Schritt müsste man sich Gedanken machen, wie man die einzelnen Dateien mit einem bestimmten Ordner verknüpft. Nur anhand des Ordnernamens funktioniert da ja nicht, weil ein Ordnername ja mehrfach vorkommen kann (wenn auch nicht innerhalb der gleichen Struktur). Beispiel: Zitat:
Wäre super! |
Re: XML-Struktur in Objekte verwalten
Hallo Christian,
Ich versuche, dir zur folgen, aber ganz komme ich nicht mit. Alle diese Eigenschaften des Objektes...
Delphi-Quellcode:
... wären ja nicht nötig, wenn du die Struktur, also die
type
TOrdner = class(TObject) Ordnername : String; Expanded: Boolean; Unterordner : TOrdner; Dateien : TDatei; end; Art der Gliederung von Ordnern und Dateien separat verwaltest, also etwa im TreeView selbst. Das Verknüpfen der Dateien zu einem Ordner wäre zu vergleichen mit Blättern an einem Ast. Welches Blatt zu welchem Ast gehört, ist ja letztendlich in deiner Datei gespeichert. Würdest du es in eine Datenbank legen, wäre die Vergabe einer ID und einer ParentID nötig, um den Baum wieder korrekt zusammenzusetzen. Auch das Zuordnen bzw. Unterscheiden, ob es sich um eine Datei oder einen Ordner handelt, könntest du unkompliziert innerhalb einer einzigen Klasse mittels eines Flags händeln.
Delphi-Quellcode:
Soweit ich weiß, sind in Windows eigentlich ja alles
type
TFile = class(TObject) Name : String; Expanded: Boolean; IsFolder: Boolean; end; nur Dateien -- auch die Ordner. Diese Datein werden nur als Ordner gekennzeichnet und entsprechend gehandhabt. Mit der obigen Klasse kannst du also wie ich schon im Thread davor beschrieben habe, das Objekt TFile erstellen und ihm zum Zeitpunkt der Erstellung sagen, ob es als Ordner oder Datei fungieren soll. Einzelne Eigenschaften könntest du mit festen Integer-Werten belegen und separat zuordnen. Oder willst du generell eine real existierende Ordnerstuktur einlesen? In Deinem Beispiel mit Fahrzeug / Auto / Verkäufe etc. wird für mich noch nicht deutlich, wo und warum es sich um Ordner und Dateien handelt. Für mich ist dass nur eine Liste von Kategorieren, oder verstehe ich dich da falsch? Grüße Jürgen |
Re: XML-Struktur in Objekte verwalten
Hi,
ich glaube Yheeky will das nicht in der Treeview speichern, sondern unabhängig. @Yheeky
Delphi-Quellcode:
aber das ist nicht richtig, denn dein Unterordner ist ja nicht nur einer, sondern eine Liste, genauso wie deine Dateien.
type
TOrdner = class(TObject) Ordnername : String; Expanded: Boolean; Unterordner : TOrdner; Dateien : TDatei; end; also
Delphi-Quellcode:
d.h. Du hast für die Ordnergeschichten 2 Objekte nötig
type
TOrdner = class(TObject) Ordnername : String; Expanded: Boolean; Unterordner : TOrdnerListe; Dateien : TDateiListe; end;
Delphi-Quellcode:
dann musst Du die TOrdnerliste als Klasse bekanntmachen, dann kannst Du sie erst mal im TOrdner verwenden. Das ist eine Forward-Deklaration. Nach der Definition von TOrdner kommt dann die vollständige Definition von TOrdnerliste.
type
TOrdnerliste = class; TOrdner = class ... UnterOrdner: tOrdnerliste; end; TOrdnerListe = class ... end; Damit das klappt, müssen allerdings beide Klassen in einer Unit untergebracht sein. Sie gehören ja auch irgendwie zusammen, und sollten sich daher nicht soweit voneinander weg bewegen ;-) Gruss |
Re: XML-Struktur in Objekte verwalten
Zitat:
Habe jetzt gerade mal deinen Code getestet und bin zu folgendem Ergebnis gekommen:
Delphi-Quellcode:
Funktioniert alles soweit. Mein Beispiel-XML-Code war folgender (und das hat funktioniert):
unit Unit1;
interface uses Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms, Dialogs, JvSimpleXml, StdCtrls, ComCtrls, JclSimpleXml, Contnrs; type TOrdnerSammlung = class; TOrdner = class(TObject) public Ordnername, Icon: string; Expanded: Boolean; Unterordner: TOrdnerSammlung; constructor Create; overload; end; TOrdnerSammlung = class(TObjectlist) function GetItems: TOrdner; public property Items: TOrdner read getItems; end; type TForm1 = class(TForm) TreeView1: TTreeView; XML: TJvSimpleXML; Button1: TButton; Button2: TButton; procedure Button1Click(Sender: TObject); procedure Button2Click(Sender: TObject); private public OrdnerListe: TOrdnerSammlung; procedure WriteNode(Node: TTreeNode; Liste: TOrdnerSammlung); procedure ReadInObjects(XMLText: TJclSimpleXMLElem; OrdnerSammlung: TOrdnerSammlung); end; var Form1: TForm1; implementation {$R *.dfm} function TOrdnerSammlung.GetItems: TOrdner; begin end; constructor TOrdner.Create; begin Unterordner := TOrdnersammlung.Create(True); end; procedure TForm1.WriteNode(Node: TTreeNode; Liste: TOrdnerSammlung); var I: Integer; newTreeNode: TTreeNode; begin if Liste.Count > 0 then for I := 0 to Liste.Count - 1 do begin newTreeNode := TreeView1.Items.AddChild(Node, TOrdner(Liste[I]).Ordnername); newTreeNode.ImageIndex := StrToInt(TOrdner(Liste[I]).Icon); if TOrdner(Liste[I]).Unterordner.Count > 0 then WriteNode(newTreeNode, TOrdner(Liste[I]).Unterordner); end; end; procedure TForm1.ReadInObjects(XMLText: TJclSimpleXMLElem; OrdnerSammlung: TOrdnerSammlung); var I, J: Integer; newFolder: TOrdner; begin // Wenn die XML-Struktur noch Daten enthält if XMLText.Items.Count > 0 then for I := 0 to XMLText.Items.Count - 1 do begin // Wenn es sich um einen Ordner handelt if XMLText.Items[I].Name = 'Ordner' then begin if XMLText.Items[I].Properties.Count > 0 then begin // Neues Ordnerobjekt erstellen newFolder := TOrdner.Create; for J := 0 to XMLText.Items[I].Properties.Count - 1 do begin // Der Ordnername wird ausgelesen if XMLText.Items[I].Properties[J].Name = 'Name' then newFolder.Ordnername := XMLText.Items[I].Properties[J].Value; if XMLText.Items[I].Properties[J].Name = 'Expanded' then if XMLText.Items[I].Properties[J].Value = 'True' then newFolder.Expanded := True else newFolder.Expanded := False; if XMLText.Items[I].Properties[J].Name = 'Icon' then newFolder.Icon := XMLText.Items[I].Properties[J].Value; end; end; end; // Fügt der Liste das Ordnerobjekt hinzu OrdnerSammlung.Add(TOrdner(newFolder)); // Auf Unterordner prüfen if XMLText.Items[I].Items.Count > 0 then // Wenn es sich um einen Ordner handelt if XMLText.Items[I].Name = 'Ordner' then ReadInObjects(XMLText.Items[I], newFolder.Unterordner); end; end; procedure TForm1.Button1Click(Sender: TObject); begin XML.LoadFromFile(ExtractFilePath(Application.ExeName) + 'Test.xml'); Ordnerliste := TOrdnerSammlung.Create(True); ReadInObjects(XML.Root, Ordnerliste); Button2.Enabled := True; end; procedure TForm1.Button2Click(Sender: TObject); begin TreeView1.Items[1].DeleteChildren; WriteNode(TreeView1.Items[1], Ordnerliste); end; end.
XML-Code:
Ich frage mich gerade nur, warum das schon funktioniert, obwohl ich in GetItems noch garnichts stehen habe? :gruebel: Wofür brauche ich es dann bzw. warum erwartet property Items ein read?
<?xml version="1.0" encoding="ISO-8859-1"?>
<Daten> <Ordner Name="Autos" Expanded="True" Icon="15"> <Ordner Name="Meine Autos" Icon="16"/> <Ordner Name="Andere Autos" Icon="17"/> </Ordner> </Daten> |
Alle Zeitangaben in WEZ +1. Es ist jetzt 07: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-2025 by Thomas Breitkreuz