Delphi-PRAXiS
Seite 2 von 2     12   

Delphi-PRAXiS (https://www.delphipraxis.net/forum.php)
-   Sonstige Fragen zu Delphi (https://www.delphipraxis.net/19-sonstige-fragen-zu-delphi/)
-   -   Delphi XML-Struktur in Objekte verwalten (https://www.delphipraxis.net/119288-xml-struktur-objekte-verwalten.html)

Hansa 24. Aug 2008 01:14

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.

Pfoto 24. Aug 2008 09:18

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:
type
  TOrdner = class(TObject)
    Ordnername : String;
    Expanded: Boolean;
  end;
In dem Fall würden ja alleine die Infos im gefüllten TreeView
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:
NewTreeNode:= aTreeView.Items.AddChildObject(aParent, 'Nodename', Pointer);
Du könntest also beim Füllen des TreeViews ein Ordner-Objekt
erstellen und dessen Pointer an den Knoten dranhängen, etwa so:

Delphi-Quellcode:
     
      { 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);
Dabei habe ich das Ordner-Objekt so deklariert:

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 TVirtualStringTree
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:
 
  { 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);
Im obigen Fall würde jetzt beides mal das gleiche angezeigt,
aber du kannst ja dein Objekt wie gewünscht aufbauen.



Grüße
Jürgen

Yheeky 24. Aug 2008 15:54

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:

Zitat von Pfoto
Nehmen wir an, diese Infos soll Dein Objekt halten:
Delphi-Quellcode:
type
  TOrdner = class(TObject)
    Ordnername : String;
    Expanded: Boolean;
  end;
In dem Fall würden ja alleine die Infos im gefüllten TreeView
aussreichen, d.h. du bräuchtest eigentlich nicht noch Objekte anlegen,
sondern könntest bei Bedarf direkt auf den Node des TreeViews zugreifen.

Stimmt, bei diesem Aufbau nicht, aber nach genauerer Überlegung müsste der Aufbau ja wiefolgt sein:

Delphi-Quellcode:
type
  TOrdner = class(TObject)
    Ordnername : String;
    Expanded: Boolean;
    Unterordner : TOrdner;
    Dateien : TDatei;
  end;
Die Dateien müssen ja noch bedacht werden und deswegen glaube ich wäre ein objektorientierter Ansatz nicht schlecht.
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:

+ Fahrzeug
-- Auto
---- Verkäufe
-- Fahrrad
---- Verkäufe
Soweit mein Problem - vielleicht hast du oder auch jemand anderes noch eine Idee für die Umsetzung (egal ob objektorientiert oder nicht).

Wäre super!

Pfoto 24. Aug 2008 17:12

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:
type
  TOrdner = class(TObject)
    Ordnername : String;
    Expanded: Boolean;
    Unterordner : TOrdner;
    Dateien : TDatei;
  end;
... wären ja nicht nötig, wenn du die Struktur, also die
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:
type
  TFile = class(TObject)
    Name : String;
    Expanded: Boolean;
    IsFolder: Boolean;
  end;
Soweit ich weiß, sind in Windows eigentlich ja alles
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

thkerkmann 24. Aug 2008 18:22

Re: XML-Struktur in Objekte verwalten
 
Hi,

ich glaube Yheeky will das nicht in der Treeview speichern, sondern unabhängig.

@Yheeky
Delphi-Quellcode:
type
  TOrdner = class(TObject)
    Ordnername : String;
    Expanded: Boolean;
    Unterordner : TOrdner;
    Dateien : TDatei;
  end;
aber das ist nicht richtig, denn dein Unterordner ist ja nicht nur einer, sondern eine Liste, genauso wie deine Dateien.

also
Delphi-Quellcode:
type
  TOrdner = class(TObject)
    Ordnername : String;
    Expanded: Boolean;
    Unterordner : TOrdnerListe;
    Dateien : TDateiListe;
  end;
d.h. Du hast für die Ordnergeschichten 2 Objekte nötig

Delphi-Quellcode:
type
  TOrdnerliste = class;

  TOrdner = class
    ...
    UnterOrdner: tOrdnerliste;
  end;

  TOrdnerListe = class
    ...
  end;
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.
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

Yheeky 25. Aug 2008 08:18

Re: XML-Struktur in Objekte verwalten
 
Zitat:

Zitat von thkerkmann
Hi,

ich glaube Yheeky will das nicht in der Treeview speichern, sondern unabhängig.

Richtig! Ich möchte die Nachrichten dann in einer ListView anzeigen lassen.

Habe jetzt gerade mal deinen Code getestet und bin zu folgendem Ergebnis gekommen:

Delphi-Quellcode:
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.
Funktioniert alles soweit. Mein Beispiel-XML-Code war folgender (und das hat funktioniert):

XML-Code:
<?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>
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?


Alle Zeitangaben in WEZ +1. Es ist jetzt 11:21 Uhr.
Seite 2 von 2     12   

Powered by vBulletin® Copyright ©2000 - 2024, Jelsoft Enterprises Ltd.
LinkBacks Enabled by vBSEO © 2011, Crawlability, Inc.
Delphi-PRAXiS (c) 2002 - 2023 by Daniel R. Wolf, 2024 by Thomas Breitkreuz