![]() |
Komponente mit Objekten, die Eigenschaften der Komponente benötigen
Hi,
der Titel ist etwas unglücklich, aber ich weiß nicht, wie ich meine Frage in einem Satz darstellen soll. Ich schreibe mir grad eine grafische Komponente zur Darstellung eines Urlaubsplans. In dieser Komponente erzeuge ich mir eine ObjectList mit Eintragstype (Urlaub, Krank, Lehrgang, ...) die dann solche Sachen wie Farbe usw. beinhalten. Dann soll diese Komponente natürlich auch eine Objectlist für die eigentlichen Einträge haben, die dann z.B. Beginn, Ende, usw. beinhalten. Und dann soll dieses Entrags-Object auch eine Eigenschaft haben, die den Eintragstyp festlegt. Diese soll aber aus der oben genannten Objectliste stammen. Wie kann man so was machen? Ich müsste ja im Create des Eintrags die Eintragstypliste übergeben. Mir ist nur nicht ganz klar, wie ich das machen könnte. Kann mir da einer auf die Sprünge helfen? |
AW: Komponente mit Objekten, die Eigenschaften der Komponente benötigen
Deine Eintragstypen sind ja soetwas wie Templates. Tolle Sache!
Dafür gibt es eine Klasse, die diese Templates verwaltet (TemplateManager). Die Klasse hat eine Methode
Delphi-Quellcode:
Der Urlaubsplan instantiiert einen TemplateManager. Im OI kannst Du die Farben für die einzelnen Eintragstypen (TTemplateType) dann konfigurieren.
//
Function Template(aTemplateType : TTemplateType) : TLayoutTemplate; // Nun erstellst Du einen Eintrag im Urlaubsplan. Dem Eintrag gibst Du den TemplateManager mit. Nun kannst Du im Eintrag einen Eintragstyp (TTemplateType) auswählen (Urlaub, Krankheit, Blaumachen etc.). Der Eintrag holt sich dann zum Zeichnen (also in seinem Paint z.B.) vom Templatemanager jeweils das entsprechende TLayoutTemplate ab und zeichnet sich entsprechend. So kannst Du das Layout ändern oder den Eintragstyp und hast immer sofort alles richtig dargestellt. |
AW: Komponente mit Objekten, die Eigenschaften der Komponente benötigen
Am Einfachsten geht das wohl mit einer Collection.
Ich glaub so ging das in etwa
Delphi-Quellcode:
Eventuell mußte man noch den Property-Reader dafür schreiben, damit die Daten in der DFM landen, falls das nicht automatisch funktioniert. :gruebel:
TDeineDaten = class(TCollectionItem)
property Name: string; // z.B. 'Urlaub' property Farbe: TColor; end; TDeinUrlaubsplan = class(TComponent) property Eintragstypen: TCollection read FEintragstypen write FEintragstypen; end; //im Contructor FEintragstypen := TCollection.Create(TDeineDaten); (notfalls mal bei TListView.Columns abgucken) Und für Collections gibt es bereits einen fertigen Standard-Property-Editor, für das Hinzufügen/Bearbeiten von Items. |
AW: Komponente mit Objekten, die Eigenschaften der Komponente benötigen
Wie wärs ganz klassisch? Ich würde mir eine Basisklasse mit virtuell abstrakten Methoden anlegen. TUrlaub, TKrank, TLehrgang usw. sind davon abgeleitet und überschreiben diese Methoden. Diese Klassen verfügen über eine Methode Draw. Dann gibt es eine Liste in der diese Items hinzugefügt werden können. Diese Liste hat ebenfalls eine Methode Draw. Zum Hinzufügen von Items aus anderen Listen kann die Liste zum Beispiel Methoden AddFromEintragsList o.ä. haben oder es gibt Konvertierungsmöglichkeiten EintragItemToListItem. Je nachdem welches Create ein Item verwendet weiß die Liste so "ganz von allein" ob es sich um Urlaub, Krank, oder Lehrgang handelt.
|
AW: Komponente mit Objekten, die Eigenschaften der Komponente benötigen
Jo, und nun möchte man ausnahmsweise den Eintragstypen 'Betriebsausflug' hinzufügen. Leider muss man bei deiner Lösung dann an den Quelltext ran.
|
AW: Komponente mit Objekten, die Eigenschaften der Komponente benötigen
Tell me about it... Diese Lösung hat doch gerade den Vorteil daß die Liste NICHT geändert werden muß?
|
AW: Komponente mit Objekten, die Eigenschaften der Komponente benötigen
Ich denke, die Fragestellung ist noch zu unscharf.
Hast Du eine Skizze? Wie soll Deine Komponente aussehen? Wo sollen die Daten herkommen/gespeichert werden? Wir immer 1 Monat dargestellt oder ist das flexibler? Gibt es überlappungsmöglichkeiten (Urlaub+Krank)? Soll der Bearbeiter das graphisch bearbeiten können (ähnlich Outlook-Kalender)? Collections musst Du eigentlich nur verwenden, wenn Du die Daten auch zur Designtime bearbeiten willst. Das vermute ich eher mal nicht - oder? |
AW: Komponente mit Objekten, die Eigenschaften der Komponente benötigen
Zitat:
Zitat:
Diese Klasse hat eh nur eine Paint-Methode und unterscheidet sich nur in der Wahl der Hintergrundfarbe und -textur sowie Textausprägung und -farbe. Vielleicht noch Sparkling-Effekte o.ä., aber das ist eine einzige banale Klasse. Über die editierbaren Eigenschaften steuerst Du das Aussehen. |
AW: Komponente mit Objekten, die Eigenschaften der Komponente benötigen
Zitat:
BTW, mein Vorschlag war eher an den TE gerichtet und weniger an dich mit der Bitte um Stellungnahme.. |
AW: Komponente mit Objekten, die Eigenschaften der Komponente benötigen
Danke für die vielen Antworten.
Nur so am Rande: Das ich mir mal eine Komponente selber geschrieben habe ist Jahre her. Sprich, zur Zeit fang ich da bei Null an. Zurück zum Thema. Okay. Zu TLayoutTemplate oder zu Template Manager spuckt meine Hilfe so gar nichts aus. Kann mir das jemand noch mal erläutern. Zur Darstellung:
Code:
So hätte ich es mir vorgestellt. Das zur Laufzeit halt Eintragstypen hinzugefügt werden können.
TEintragsTypListe (TObjectList) <--------------------------+
| | +-->TEintragsTyp (TObject) | | | | | +-->Bezeichnung: string; | | +-->Farbe: TColor; | | +-->... | (Oder nur ein TObject, +-->Count: Integer; | dass dann auf den | TEintragstyp zeigt) TEintragListe (TObjectList) | | | +-->TEintrag (TObject) | | | | | +-->Text: string; | | +-->TEintragsTypListe (TObjectList) Zeigt auf ------+ | +-->EintragsTypIndex: Integer; +-->Count: Integer TUrlaubskalender (TObjectList) | +-->Eintragstypen: TEintragsTypList +-->Eintraege: TEintragListe +-->...noch ein paar globale Wenn dann aber Einträge hinzugefügt werden, muß ja irgendwie im Eintrag ein Zeiger auf die Eintragstypenliste mitgegeben werden. Das könnte man zwar auch über das OnCreate machen, sieht für mich aber ein irgendwie unschön aus. Meine Frage zielt also darauf ab, wie man so was am elegantesten macht. Mir fällt da grad noch einen andere Frage zu ein: Wenn ich z.B. ein Eintrag hinzufüge, möchte ich gerne, dass die Komponente seine Paint-Routine aufruft. Da Eintrag ja eine eigene Klasse ist, kann sie ja nicht von welcher Klasse sie erzeugt ist. Oder doch? |
AW: Komponente mit Objekten, die Eigenschaften der Komponente benötigen
Und genau für sowas sind doch die Collections da.
> Eine Liste von eigenen Klassen eines Typs. Man kann das natürlich auch alles selber machen, z.B. über Objektlisten, aber wenn man das auch noch über den OI bedienen will, würde man dann noch anfangen sich einen passenden Property-Editor zu schreiben, welcher mit dieser Liste und den enthaltenen Klassen umgehen kann. |
AW: Komponente mit Objekten, die Eigenschaften der Komponente benötigen
Die wichtigsten Fragen sind aus meiner Sicht (immer) noch offen...
Wozu eigentlich eine Komponente? Die brauchst Du ja eigentlich nur, wenn Du eine universelle Einsetzbarkeit benötigst oder wenn Du die Einträge zur Designtime eintragen willst. Willst Du die Komponente dann zur Designtime konfigurieren (mögliche Eintragstypen einrichten) oder soll das der Enduser nach Bedarf machen dürfen. Das hier Zitat:
Also bringt es Dir nichts, n feste Klassen zu definieren (zu kompilieren), da der Enduser dann ja nicht weitere Klassen hinzufügen kann. In dem Fall brauchst Du keine Komponente oder jedenfalls keine, die zur Designtime über eine Collection konfiguriert wird. Collection vereinfachen gegenüber Objektlisten das Speichern und Bearbeiten von Einträgen in der IDE. Wenn man diese Funktionalität nicht braucht, sollte man m.E. auch keine Collections verwenden. Für mich klingt das eher nach einer Anwendung mit einer relationalen Datenbank und passenden Tabellen. Natürlich kann man die Daten und Beziehungen auch in Objekten ablegen, dann muss man halt ID´s definieren, wenn Beziehungen nach dem Speichern und erneutem Öffnen wieder hergestellt werden müssen. |
AW: Komponente mit Objekten, die Eigenschaften der Komponente benötigen
Zitat:
Aber da ich sowas noch nie so richtig gemacht habe, wollte ich mich mal damit beschäftigen. Kann ja nicht schaden. :-D Und auch wenn sich dann manche Dinge etwas aufwendiger gestalten, als wenn man das ohne Komponente realisieren würde, will ich es trotzdem versuchen. Zwar werden die Einträge und die Eintragstypen später sicherlich aus eine DB bestückt, so möchte ich trotzdem auch zur DT im IO auch welche hinzufügen können, die dann auch zur DT in der Komponente sichtbar sind. Auch wenn man es nicht zwangsläufig braucht. Ist halt gleichzeitig ein Übungsprojekt. |
AW: Komponente mit Objekten, die Eigenschaften der Komponente benötigen
Ok, dann ist das natürlich so in Ordnung. :-)
Ein konkretes Problem sehe ich aber. Wenn Du später die Daten aus einer Datenbank holen willst wird sich das nicht mit den zur Designtime erzeugten Einträgen vertragen. Was soll dann Vorrang haben. Als Testprojekt ist das natürlich so möglich, aber der Ansatz ist m.E. nicht der sinnvollste, um Dein Zielprojekt zu realisieren. |
AW: Komponente mit Objekten, die Eigenschaften der Komponente benötigen
Zitat:
Das ich Einträge zur DT haben möchte hat 2 entscheidenden Gründe. 1. Ich will lernen wie das geht. Also wie man über den OI und ggf. einer Eingabemaske eben zur DT schon vollwertige Einträge hinzufügen kann. (Evtl. will ich ja später mal eine Komponente entwickeln, bei der das sinnvoller wäre). 2. Für die grafische Gestaltung meiner Komponente zur DT wäre es sinnvoll, wenn man ein paar Einträge einstellen kann, und die Auswirkungen von Designeigenschaften gleich bei der Entwicklung gut sehen kann. Auch das könnte man natürlich auch anderes überprüfen, aber auch hier will ich gleich mal lernen wie man das am elegantesten macht. Deswegen hoffe ich auf eure Unterstützung. Und seht es mir bitte nach, wenn ich hier und da noch ein paar blöde Fragen stelle. Aber was für manchen selbstverständlich und logisch ist, ist mir manchmal noch nicht so ganz klar. |
AW: Komponente mit Objekten, die Eigenschaften der Komponente benötigen
Ich hab das jetzt mal umgestellt auf TCollection und das gefällt mir so richtig gut :-)
Vielen Dank. Wieder was gelernt. Nun möchte ich noch was erreichen. Ich kann meiner Komponente zur DT Items für Eintragstypen (Urlaub, Krank...) hinzufügen. Ich kann auch Einträge mit den Daten Beginn und Ende (halt was ich im CollectionItem definiert habe) hinzufügen. Ich würde aber gerne im Item des Entrags aus einer Liste eine Eintragstyp auswählen, und zwar aus denen, die ich vor in den Eintragstypen angelegt habe. Ich weiß aber nicht wirklich, wie ich da dran komme bzw. wie ich so was machen könnte. Grundsätzlich würde ich das gerne so mache, wie das z.B. bei TMainMenu und den Images ist. Also meinem Eintrag eine Property für den zu verwendenden Eintragtypenlistenindex auswähle. Aber er soll mir auch nur die tatsächlich vorhanden EintragstypenlistenIDs anbieten, bzw. ich muss ja in dem Eintrag auch festlegen, welche Eintragstypenliste zu verwenden ist. Hier mal ein Beispiel wie ich das meine:
Code:
Ich weiß nicht ob das so überhaupt möglich ist.
TUrlaubsplaner
| +-->TEintragstypenList | | | +-->TEintragstyp | | | +-->Bezeichnung z.B. Urlaub | +-->ID z.B. 0 | +-->TEintrag | +-->Von (TDate) +-->Bis (TDate) +-->TypID (Über diese ID will ich dann den Typ ermitteln, bzw. im OI sollte auch nur die möglichen ID's auftauchen, vlt. sogar mit Namen dahinter. Aber dazu muß der Eintrag ja wissen, dass er die obige EintragstypenListe verwenden soll.) |
AW: Komponente mit Objekten, die Eigenschaften der Komponente benötigen
Habe ich doch
![]() |
AW: Komponente mit Objekten, die Eigenschaften der Komponente benötigen
Zitat:
Ich hab auch drauf geantwortet: Zitat:
|
AW: Komponente mit Objekten, die Eigenschaften der Komponente benötigen
Entschuldigung. Die Begriffe waren von mir, so wie ich sie benannt hätte.
TLayoutTemplate = TEintrag Template Layout Manager = Die Instanz von TEintragstypenList in deiner TUrlaubsplaner-Komponente. Wenn Du also einen neuen Eintrag erstellst übergibst Du ihm deine EintragstypenList:
Delphi-Quellcode:
Du könntest theoretisch einem Eintrag auch gleich den ganzen TUrlaubsplaner mitgeben, aber das ist kein guter Stil, denn hier kennen sich dann zwei Klassen gegenseitig und das sollte vermieden werden (zirkuläre Abhängigkeit (*)).
Procedure TUrlaubsplaner.AddEntry(aTypID : TEintragsTypID);
Var derNeueEintrag : TEintrag; Begin derNeueEintrag := TEintrag.Create (EintragsTypenList); derNeueEintrag.EintragTypID := aTypID; EintragsList.Add(derNeueEintrag); End; ... Procedure TEintrag.Paint(...); var vorlage : TEintrafsTyp; Begin vorlage := fEintragsTypenList.FindByID(this.EintragTypID); ... // Zeichne mit den Farben, Schrifttyp etc. aus der 'vorlage' End; So kennt der TUrlaubsplaner eine TEintragsTypenList und ein TEintrag kennt eine TEintragstypenList. Kein Zirkel, kein Problem. (*) Aus diesem Grund mag ich auch keine TCollection. |
AW: Komponente mit Objekten, die Eigenschaften der Komponente benötigen
Zitat:
Jetzt hab ich das auch besser verstanden. Zitat:
Beim TEintrag.Create die Typenliste mit zu übergeben hatte ich mir auch schon so vorgestellt. Werde ich gleich mal ausprobieren. Mal sehen wie weit ich komme. Aber es stellt sich mir noch ein anderen Problem: Das Neuzeichnen wenn Einträge hinzugefügt werden. Als Beispiel nehme ich mal ein TListView. Wenn ich im OI Columns oder Items hinzufüge, dann wird das sofort im ListView umgesetzt und dargestellt. So würde ich das auch gerne machen. Aber wie erfährt meine Basisklasse, dann ist der Klasse TEinträge ein Eintrag hinzugefügt wurde? Ich hab schon überlegt das über eine Windows-Message zu machen, aber da meine Basisklasse von TGraphicControl abgeleitet ist, hat sie kein Handle. |
AW: Komponente mit Objekten, die Eigenschaften der Komponente benötigen
Aus welchem Grund?
Das TCollectionItem kennt doch nicht die übergeordnete TCollection. (leider) Und ich weiß auch nicht, warum es schlecht sein soll, seine Eltern zu kennen. |
AW: Komponente mit Objekten, die Eigenschaften der Komponente benötigen
Wenn ich es richtig verstehe, ist dafür die Methode
![]() |
AW: Komponente mit Objekten, die Eigenschaften der Komponente benötigen
Damit kann nur die Collection drauf reagieren, wenn etwas in ihr geändert wird.
Die CollectionsItems haben kein Notify. Standardmäßig wissen die Items nicht ob und in welcher Collection sie sich befinden, außer man würde sich selber ein Owner/Parent-Feld in die Items einbauen und dann z.B. im Notify diese Variable setzen. Hatte mal versucht das als generische Objektvorlage umzusetzen, was bei eigenen Deklarationen geht, aber nicht wenn man von den Originaltypen erbt, also wo dann die Collections und Items sich gegenseitig kennen und auch noch die Typen/Property/Parameter richtig gecastet sind. Zwei getrennte Typen ableiten und sich gegenseitig referenzieren zu lassen war mit den Generics aber nicht so leicht möglich, vorallem wenn man sie in der VCL und speziell im FormDesigner und ObjektInspektor haben möchte, wo man dann noch das generische < und > im Namen verstecken muß. |
AW: Komponente mit Objekten, die Eigenschaften der Komponente benötigen
Wozu brauchen denn die Items ein Notify? Die Collection gibt bei Änderungen Bescheid und benennt dabei das Item und die Art der Änderung. Darauf kann man reagieren und z.B. neu zeichnen.
|
AW: Komponente mit Objekten, die Eigenschaften der Komponente benötigen
Zitat:
Es sieht bei mir zur Zeit so aus:
Delphi-Quellcode:
Wenn jetzt z.B. TUrlaubskalender.Eintraege.Add aufgerufen wird, wie bekommt denn die Klasse TUrlaubskalender das mit, denn hier existiert die Methode Paint.
unit tuUrlaubskalender;
TUrlabuskalender = class Property TEintraege: TEintraege; property TEintrastypen: TEintragstypen; propcedure Paint; end; ---- unit tuEintraege; TEintraege = class(TCollection) ... end; TEintrag = class(TCollectionItem) ... end; --- unit tuEintragstypen; TEintragstypen = class(TCollection) ... end; TEintragstyp = class(TCollectionItem) ... end; |
AW: Komponente mit Objekten, die Eigenschaften der Komponente benötigen
Gut ich könnte in der TUrlaubskalender eine Methode AddEintrag machen, die ihrerseits dann die Add-Mothode der Collection Eintraege aufruft.
Aber macht man das so? Oder gibt es noch den weg rückwärts über irgendeine Benachrichtigung. |
AW: Komponente mit Objekten, die Eigenschaften der Komponente benötigen
Indem die Collections deine Komponente kennen. Mußt du einbauen, indem du das Notify überschreibst und dort deinem Kalender sagst "du, da hat sich was geändert ... mach ma".
|
AW: Komponente mit Objekten, die Eigenschaften der Komponente benötigen
Meinst du so:
Delphi-Quellcode:
dann könnte ich ja im TEintraege.Notify ja self.FParent.Paint aufrufen, oder?Constructor TUrlaubsplan.Create; begin inherited; self.FEintraege:=TEintraege.Create(self); end; //Und im TEitraege ... FParent: TURlaubsplan; . . . constructor TEintreage.Create(Urlaubsplan: TUrlaubsplan); begin inherited; self.FParent:=Urlaubsplan; end; |
AW: Komponente mit Objekten, die Eigenschaften der Komponente benötigen
Zitat:
|
AW: Komponente mit Objekten, die Eigenschaften der Komponente benötigen
Wieso kein Event? Dann kann der Urlaubsplan dem einen Handler zuweisen, die Einträge müssen den Urlaubsplan aber gar nicht kennen, sondern führen nur den ggf. zugewiesenen Code aus.
|
AW: Komponente mit Objekten, die Eigenschaften der Komponente benötigen
Zitat:
Delphi-Quellcode:
Procedure TUrlaubsPlan.ItemChanged (Sender : TObject);
Begin Assert (Sender is TEintrag, 'Nee, Du darfst diesen Handler nur an TEintrag-Instanzen bepseln'); Repaint.... End; Procedure TUrlaubsPlan.AddEntry (...); Var derNeueEntrag : TEintrag; begin ... derNeueEintrag.OnChanged := ItemChangeD; ... End; |
AW: Komponente mit Objekten, die Eigenschaften der Komponente benötigen
@Captnemo
Ich war überrascht, dass Du Dein Projekt mal in 2 Stunden auf Collections umgestellt hast. Insofern gehe ich (ich will nicht nerven!) immer noch davon aus, dass Du etwas auf dem Holzweg bist. Collections haben eigentlich nur Nachteile - AUßER wenn es um die Bearbeitung der Einträge über einen Komponenteneditor und vor allem um das Speichern der Einträge in der dfm geht. Das geht mit Collections einfacher (oder nahezu NUR mit Collections). Alles andere geht besser mit normalen Listen. Die Einträge der Collections werden in der dfm ungefähr so gespeichert: Meine Liste - Eintrag (Vorname, Nachname, Alter) - Eintrag (Vorname, Nachname, Alter) - Eintrag (Vorname, Nachname, Alter) - Eintrag (Vorname, Nachname, Alter) Beim Laden des Formulars werden diese Einträge dann wieder hergestellt. Aber Du kannst nicht so einfach Beziehungen zwischen den Einträgen oder auf bestimmte Einträöge abbilden. Ein schönes Beispiel sind Columns. Da steht im Grid, welche Spalten dargestellt werden sollen und wie die beschriftet werden sollen. Es gibt aber nicht die Möglichkeit, über einen Componentennamen (wie Edit1 oder Panel500) auf die 3. Spaltendefinition zuzugreifen. Ich für mich habe die Einträge gedanklich eher als Records angesehen, wobei das streng genommen natürlich nicht richtig ist. Die Handhabung ist aber ähnlich. Wenn Du nun Deine Geschäftsdaten ("Eintragsarten" - ich benutze mal nicht "Typen", weil es ja hier nicht um Typen oder Klassen für den Compilers geht) dort ablegen willst macht das eigentlich nur Probleme. Aus meiner Sicht gehören dort nur Strukturanweisungen für die GUI hinein (eben z.B. die Spaltendeklarationen für ein Grid). Wenn Du willst, dann schau mal auf mein Video zu meinem Framework: ![]() Da ich die Eintragsbearbeitung dort mit meinem Databinding durchführen wollte habe ich die CollectionItems in eine normle Liste übertragen und nach der Bearbeitung wieder zurück. Wenn der Komponentenexperte geschlossen wird gibt es aber keinen Bezug mehr zwischen der alten und neuen Collection. Wenn man dies braucht muss man den Items eine eigene ID zuweisen und kann so prüfen, welche Einträge neu sind oder geändert wurden. Also: Der Umgang mit Collections ist umständlich und nur sinnvoll, wenn man zur Designtime einen Komponenteneditor nutzt und die Einträge in der dfm speichern will. Ich habe natürlich nichts degen, dass Du Collections nutzt oder testest aber ich glaube, Dein Anwendungsfall ist nicht der richtige dafür... Hast Du denn einen Komponenteditor für Deine Items? Wenn ja und wenn Du das dann mal mit Geschäftsdaten-Datei kombinieren willst dann müssten Deine Items irgendeine eindeutige ID erhalten, damit Du die irgendwie weiterverarbeiten kannst. |
Alle Zeitangaben in WEZ +1. Es ist jetzt 21:16 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