Delphi-PRAXiS

Delphi-PRAXiS (https://www.delphipraxis.net/forum.php)
-   Algorithmen, Datenstrukturen und Klassendesign (https://www.delphipraxis.net/78-algorithmen-datenstrukturen-und-klassendesign/)
-   -   Delphi VirtualStringTree: Dynamisches Array in Klasse verwenden? (https://www.delphipraxis.net/163990-virtualstringtree-dynamisches-array-klasse-verwenden.html)

100nF 24. Okt 2011 18:02

VirtualStringTree: Dynamisches Array in Klasse verwenden?
 
Hallo zusammen,

Ich beschäftige mich wiedermal mit der VirtualStringTree. Dabei arbeite ich mit einer Klasse dieser Form (Hab Sie der Übersichtlichkeit halber auf nur 2 Eigenschaften gekürzt):

Delphi-Quellcode:
type
  TTeil = class (TComponent)
      private
          fID:                  Integer;
          fName:                String;
        published
          property ID: integer read fID write fID;
          property Name: string read fName write fName;
      end;
      pTeil = ^TTeil;
Das Hinzufügen von Datensätzen zur VST geschieht genau so wie es im damaligen Stammtisch-Video gezeigt wurde:
Delphi-Quellcode:
Teil := TTeil.create(nil);
Teil.ID := TeileID;
Teil.Name := 'BlaBla' ;
VST_Teile.AddChild(nil,Teil);
Und so werden die Nodes gespeichert und geladen:
Delphi-Quellcode:
procedure TF_Main.VST_TeileSaveNode(Sender: TBaseVirtualTree;
  Node: PVirtualNode; Stream: TStream);
var
  Teil: TTeil;
begin
  Teil:=TTeil(Sender.GetNodeData(node)^);
  Stream.WriteComponent(Teil);
end;

procedure TF_Main.VST_TeileLoadNode(Sender: TBaseVirtualTree;
  Node: PVirtualNode; Stream: TStream);
var
  Teil: TTeil;
  p: pTeil;
begin
  Teil:=Stream.ReadComponent(nil) as TTeil;
  p:=sender.GetNodeData(node);
  p^:=Teil;
end;
Das funktioniert soweit auch alles.
Wie sich vielleicht schon vermuten lässt, handelt es sich bei den Datensätzen um Teile. Es soll also eine kleine Bauteilverwaltung werden ;) Nun kann man das selbe Teil ja auch von verschiedenen Anbietern kaufen, was dann bedeutet, dass ich jedem Bauteil (Datensatz) mehrere Lieferanten, Bestellnummern und Preise zuordnen können muss. Da ich mich dabei nicht auf z.B. maximal 3 Anbietern festlegen will, muss das ganze ja dynamisch werden. Also mit Dynamischen Arrays würde ich mal schätzen.

Und genau da liegt jetzt mein Problem. Dem VST muss ja ganz am Anfang mal die Grösse zugewiesen werden:
Delphi-Quellcode:
VST_Teile.NodeDataSize := SizeOf(TTeil);

So, und wenn nun mein TTeil plötzlich dynamisch wird, wird wohl diese Initialisierung scheitern.

Übrigens wäre es schön wenn ich die, ich nenne sie mal Einkaufsinformationen, auch mit einer Klasse erstellen könnte, da ich dann diese Informationen wiederum ganz einfach in einer separaten VST darstellen kann:
Delphi-Quellcode:
type
  TEinkaufsinformation = class (TComponent)
      private
          fLieferantenID:      Integer;
          fBestellnummer:      String;
          fPreis:              Extended;
      published
          property LieferantenID: integer read fLieferantenID write fLieferantenID;
          property Bestellnummer: String read fBestellnummer write fBestellnummer;
          property Preis: Extended read fPreis write fPreis;
      end;
Und dann mache ich einfach mal ein Array dazu:
Delphi-Quellcode:
type TEinkaufinformationen = Array of TEinkaufsinformation;

Das war jetzt einfach so ein bisschen Brainstorming, ich weiss nämlich nicht was ich nun mit diesem Array genau machen soll ;-) Irgendwie müsste das jetzt der Klasse TTeil hinzugefügt werden...nur wie?

Bitte schlagt mich nicht. Ich befürchte dass mein Ansatz schon ziemlich falsch sein könnte, mir fehlt einfach die Erfahrung. Ich habe schon nach Ansätzen im Internet gesucht, aber ich befürchte mein Vorhaben ist da schon sehr speziell, das ist schwierig da irgendwas ähnliches zu finden.

Also: Wie kann ich der Klasse TTeil beibringen, dass Sie einen dynamischen Inhalt annimmt und diesen auch korrekt speichern / laden kann?

Ich wäre extrem dankbar wenn mir da jemand auf die Sprünge helfen könnte!

mfg

ConnorMcLeod 24. Okt 2011 18:11

AW: VirtualStringTree: Dynamisches Array in Klasse verwenden?
 
Würde anstatt eines Arrays eine TList nehmen.
Edit: oder eine TObjectList.

Furtbichler 24. Okt 2011 18:26

AW: VirtualStringTree: Dynamisches Array in Klasse verwenden?
 
Ich kenn mich mit VST nicht aus, aber anstatt dem Objekt würde ich nur eine ID im Knoten speichern. Die Daten selbst sind dann in einer separaten Liste.

Ist es das, was ConnorMcLeod meint?

Man sollte grundsätzlich Datenhaltung und Visualisierung strikt trennen.

100nF 24. Okt 2011 18:40

AW: VirtualStringTree: Dynamisches Array in Klasse verwenden?
 
Zitat:

Würde anstatt eines Arrays eine TList nehmen.
Edit: oder eine TObjectList.
Also eine TList wäre halt nicht so toll weil ich da ja nur Strings speichern kann.
TObjectList kenne ich noch nicht, müsste ich mir erst mal anschauen. Aber diese wird dann doch auch dynamisch sein oder? Ich weiss dann eben nicht was ich bei der NodeDataSize angeben muss.

Mein TTeil hat nun ja eine feste, vordefinierte Grösse. Und genau diese Grösse gebe ich ja dann bei der VST_Teile.NodeDataSize an. Nur wie mache ich das wenn TTeil dynamisch ist?

Oder kriege ich es irgendwie hin, dass TTeil gar nicht erst dynamisch wird? Wohl eher nicht oder? Wäre irgendwie ja unlogisch... ;)

Zitat:

Ich kenn mich mit VST nicht aus, aber anstatt dem Objekt würde ich nur eine ID im Knoten speichern. Die Daten selbst sind dann in einer separaten Liste.
OK auf die Idee bin ich noch gar nicht gekommen^^ Eine separate Liste mit den Einkaufsinformationen aller Bauteile, und dann jeweils nur die Einträge anzeigen, die zum markierten Artikel gehören? Wäre eine Möglichkeit, allerdings finde ich Sie etwas umständlich. Ein direktes Zuweisen der Einkaufsinformationen zum jeweiligen Artikel ist irgendwie viel schöner und übersichtlicher.

Zitat:

Man sollte grundsätzlich Datenhaltung und Visualisierung strikt trennen.
Genau das ist eben bei der VST nicht der Sinn. Da hat man alles in einem, und man "sagt" dann der Komponente, welche Datensätze sie wie anzeigen soll, wie sie sich genau verhalten soll usw.

daywalker9 24. Okt 2011 18:43

AW: VirtualStringTree: Dynamisches Array in Klasse verwenden?
 
Zitat:

Zitat von urbanbruhin (Beitrag 1132308)
Zitat:

Würde anstatt eines Arrays eine TList nehmen.
Edit: oder eine TObjectList.
Also eine TList wäre halt nicht so toll weil ich da ja nur Strings speichern kann


Nein, Du kannst da nicht nur Strings speichern. Du kannst dort ebenso Records, Klassen etc.. drin ablegen.

100nF 24. Okt 2011 19:35

AW: VirtualStringTree: Dynamisches Array in Klasse verwenden?
 
Ach so, ich hab da an TStringList gedacht, da ich auch TList noch nicht kannte :D
Aber das scheint ja eine Art Liste von Pointern zu sein. Nur versteh ich nicht wie ich das verwenden soll, ich will ja nicht die Pointer meiner Daten abspeichern, sondern die Daten selber....:?:

daywalker9 24. Okt 2011 19:46

AW: VirtualStringTree: Dynamisches Array in Klasse verwenden?
 
Korrekt, es ist eine Liste von Pointern auf deine Daten. Du erzeugst wie gewohnt deine Objekte und fügst Sie per .Add hinzu und kannst später per Items[index] draufzugreifen. So kommst Du dann an deine Daten ran.

100nF 24. Okt 2011 21:06

AW: VirtualStringTree: Dynamisches Array in Klasse verwenden?
 
Naja das Problem ist dann aber dass diese Daten nicht mit den TTeil-Daten zusammen abgespeichert und geladen werden. Das müsste ich dann "von Hand" machen, was irgendwie auch nicht sehr elegant ist. Und ausserdem ist es wieder eine Fehlerquelle mehr...

Die Einkaufsinformationen sollten wenn möglich schon auch direkt mit den TTeil-Eigenschaften abgespeichert und wieder geladen werden.

Ich dachte das ist doch bestimmt keine grosse Sache, aber so langsam bin ich da nicht mehr so zuversichtlich ;)

ConnorMcLeod 24. Okt 2011 21:23

AW: VirtualStringTree: Dynamisches Array in Klasse verwenden?
 
Daten und GUI sollte man IMMER voneinander trennen. Stell Dir nur mal vor, Du willst/sollst die Daten in sechs Monaten anders präsentieren. Dann müsstest Du entweder alles neu erfinden oder einen unsichtbaren VST im Hintergrund mitlaufen lassen...

Aus Erfahrung wird aus zusammengehörenden Daten ein Record und aus diesem Record bald eine Objektklasse, damit der Record auch etwas intelligenter wird. Die Instanzen dieser Klasse hast Du dann entweder in einem Array (=schneller sequentieller Zugriff) oder in einer Liste (= Add/Delete/Sort komfortabler). Das Data vom VST ist dann immer nur ein Pointer auf eines dieser Objekte.

Hoffe, das hilft.

100nF 24. Okt 2011 22:19

AW: VirtualStringTree: Dynamisches Array in Klasse verwenden?
 
Ja im professionellen Bereich wird das wohl ein wichtiges Kriterium sein, dass GUI und Daten strikte getrennt sind. Aber ich denke für ein kleines Privatprojekt das einfach sein Zweck erfüllen soll kann man da auch eine Ausnahme machen ;-)

Die VST-Komponente bietet da halt schon sehr viel Komfort:
  • Speichern und Laden aller Datensätze mit wenigen Zeilen Code
  • Einfaches Erstellen von Unterknoten, welche auch automatisch wieder richtig geladen werden
  • Änderungen in der GUI wirken sich automatisch auch auf die "Datenbank" aus
  • Integrierte Filter- und Suchfunktion
  • Einflussnahme auf die grafische Darstellung ganz einfach und umfangreich

Also zum Darstellen der Daten will ich keine andere Komponente verwenden. Und wenn ich sie schon zum darstellen nehme, warum dann nicht auch gerade für die Datenverwaltung, wenn es doch auch viel einfacher ist als eine separate Datenbank?

Das "Richtige" für eine Bauteile-Verwaltungssoftware wäre ja wohl eine echte Datenbank. Das finde ich dann aber schon sehr mühsam, alle Datensätze immer zwischen Datenbank und VST hin- und herzuschieben. Wie gesagt, es soll ja nur ein kleines Privatprojekt werden... ;)

Ausserdem lässt sich ja auch eine Export-Funktion relativ leicht programmieren, so könnte man die Datensätze wenigstens in einem gescheiten Format abspeichern, falls das mal notwendig sein sollte.

himitsu 24. Okt 2011 22:26

AW: VirtualStringTree: Dynamisches Array in Klasse verwenden?
 
Zitat:

Zitat von urbanbruhin (Beitrag 1132342)
warum dann nicht auch gerade für die Datenverwaltung, wenn es doch auch viel einfacher ist als eine separate Datenbank?

Muß ja nicht unbedingt separat sein ... man könnte auch embedded nutzen :angle:

100nF 25. Okt 2011 09:12

AW: VirtualStringTree: Dynamisches Array in Klasse verwenden?
 
Zitat:

Zitat von himitsu (Beitrag 1132344)
Muß ja nicht unbedingt separat sein ... man könnte auch embedded nutzen :angle:

Ja könnte man...aber da sehe ich dann keine grossen Vorteile mehr gegenüber der VST-Variante :)

Naja sonst mache ich es halt doch mit einer separaten Liste nur für die Einkaufsinformationen...

Danke schonmal für die Antworten!

mfg

himitsu 25. Okt 2011 09:36

AW: VirtualStringTree: Dynamisches Array in Klasse verwenden?
 
Das Problem ist eher, wenn du die Daten fest an eine Komponente bindest:
- wurde daran was verändert
- gibt es diese Komponente nicht mehr
- oder läßt sie sich nicht mehr insallieren (neues Delphi oder gar was Anderes, wie z.B. C#)
das war's das mit den Daten (oder man muß versuchen sie zu konvertieren)

PS: Geht etwas in deiner Speicherroutine schief, dann sind die Daten futsch.
Ich vermute mal, daß du kein "sicheres" Speichern durchführst. (vielleicht sollte ich mal meinen entsprechenden FileStream hier hochladen)

Lemmy 25. Okt 2011 09:44

AW: VirtualStringTree: Dynamisches Array in Klasse verwenden?
 
hi,

Zitat:

Zitat von urbanbruhin (Beitrag 1132302)
Und genau da liegt jetzt mein Problem. Dem VST muss ja ganz am Anfang mal die Grösse zugewiesen werden:
Delphi-Quellcode:
VST_Teile.NodeDataSize := SizeOf(TTeil);
So, und wenn nun mein TTeil plötzlich dynamisch wird, wird wohl diese Initialisierung scheitern.


echt? Rate mal was folgendes für ne Ausgabe produziert:

Delphi-Quellcode:
  Memo1.Lines.Add(IntToStr(SizeOf(TForm)));
  Memo1.Lines.Add(IntToStr(SizeOf(TMemo)));
  Memo1.Lines.Add(IntToStr(SizeOf(TStrings)));
Und dann die Erklärung: Du ermittelst mit SizeOf NICHT die Größe einer Instanz sondern die Größe des Pointers (!) der auf die Instanz zeigt! Von daher spielt es keine Rolle wie viele Eigenschaften/Methoden/Arrays deine Klasse hat - der Pointer hat immer 4 Bytes.... (keine Regel ohne Außnahme: Win64 Code ;-))

Und meine Vorredner haben natürlich Recht - Visualisierung und Datenhaltung sollten getrennt voneinander sein, d.h. Die Teile speicherst Du in einer ObjectList, die Du in einer Lade-Methode füllst und anschließend verwendest Du die Objectlist um die Instanzen in den Tree zu hängen.

Grüße

Medium 25. Okt 2011 10:28

AW: VirtualStringTree: Dynamisches Array in Klasse verwenden?
 
Ich nehme an, TTeil ist ein Record. In diesem Fall gibt SizeOf tatsächlich die Größe der Instanz an, weil potenziell Stack-Objekt.

DeddyH 25. Okt 2011 10:31

AW: VirtualStringTree: Dynamisches Array in Klasse verwenden?
 
Aus dem Ausgangspost:
Zitat:

Delphi-Quellcode:
type
  TTeil = class (TComponent)


Medium 25. Okt 2011 10:59

AW: VirtualStringTree: Dynamisches Array in Klasse verwenden?
 
Ups :angel2:

DeddyH 25. Okt 2011 11:02

AW: VirtualStringTree: Dynamisches Array in Klasse verwenden?
 
Kann ja mal vorkommen :zwinker:

100nF 25. Okt 2011 16:18

AW: VirtualStringTree: Dynamisches Array in Klasse verwenden?
 
OKay Okay...

jetzt weiss ich gar nicht mehr wie ich das ganze machen soll :shock:

Ich habe im Programm jetzt schon 5 VST's das Speichern, Laden usw beigebracht und das war ja alles fürn A*** wenn ich die Daten nun separat abspeichern will :-(

Oh mann... Ich weiss nicht was ich jetzt machen soll....Muss erstmal drüber nachdenken :)

mfg

100nF 2. Nov 2011 17:11

AW: VirtualStringTree: Dynamisches Array in Klasse verwenden?
 
So, also ich glaub ich weiss jetzt wie ich es mache :D

Für die Artikel und die Einkaufsinformationen nehme ich je eine dateibasierte Datenbank. Eine andere "Tabelle" brauch ich aber noch für die Kategorien, was nichts anderes als eine TreeView ist, natürlich mit Unterknoten usw. Dies mache ich aber dann doch mit dem VST weil dieser die richtige Struktur auch gleich mitspeichern und laden kann.

Weil meine D2005 PE keine Datenbankkomponenten hat, hab ich die Gelegenheit auch gleich genutzt um mal Lazarus näher anzuschauen. Scheint eigentlich ganz ordentlich zu sein, nur halt schade dass es die JVCL-Komponenten nicht gibt...da wär so ein schöner DatenbankTreeView dabei gewesen xD naja immerhin den VST gibts für Lazarus.

Also vielen Dank euch für die Antworten! Hat zwar nicht so einfach geklappt wie ich mir das erhofft habe, aber ist ja auch nicht so schlimm ;-)

mfg

Sir Rufo 2. Nov 2011 17:35

AW: VirtualStringTree: Dynamisches Array in Klasse verwenden?
 
Dann schau dir doch mal Synopse mORMot an, wenn du eine Datenbank benötigst.

Und eine Komponente zum Anzeigen sollte man tunlichst nicht zur Datenhaltung verwenden, sondern ausschließlich als Anzeige.

100nF 2. Nov 2011 22:00

AW: VirtualStringTree: Dynamisches Array in Klasse verwenden?
 
Zitat:

Dann schau dir doch mal Synopse mORMot an, wenn du eine Datenbank benötigst.
Hmm eine etwas verwirrende Seite finde ich :cyclops: Aber ich nehme mal die Standardkomponenten von Lazarus, die scheinen mir zu genügen. Und wenn Lazarus meinen Ansprüchen genügt, dann bleibe ich auch lieber dabei weil ich dann die Projekte ziemlich einfach auch für Linux kompillieren können sollte. Ich arbeite ständig mit Linux - zum programmieren mit Delphi arbeite ich in einer VM ;) Dass die Programme auf Windows laufen ist mir allerdings lieber als reine Linux-Programme, denn Windows-Programme kriege ich auch auf Linux zum Laufen mit einem Emulator. Umgekehrt wirds wohl schwieriger...

Zitat:

Und eine Komponente zum Anzeigen sollte man tunlichst nicht zur Datenhaltung verwenden, sondern ausschließlich als Anzeige.
Ja vor etwa einer Stunde hab ich mir diesen Ruck doch auch noch gegeben. Habs eingesehen dass es so wohl besser ist :D Gibt zwar einiges mehr zum Programmieren (Baumstrukturen in Datenbanken sind mühsam) aber es ist halt schon einiges eleganter und auch weniger fehleranfällig.

mfg


Alle Zeitangaben in WEZ +1. Es ist jetzt 14:21 Uhr.

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