kommunizierende Komponenten
-
Hallo zusammen!
Ich möchte Komponenten schreiben, die miteinander kommunizieren. Zu diesem Zweck habe ich versucht Komponenten abzuleiten, die eine Property haben, in der man die andere Komponente angeben kann, mit der eine Komponente kommunizieren sollen.
Als Beispiel nehme ich hier 'mal ein StringGrid und ein Edit. (Es geht mir aber um die allgemeine Lösung des Problems, da das an mehreren Stellen sehr nützlich wäre.)
Das Edit soll immer den Wert einer bestimmten Spalte in der gerade selektierten Zeile des Grids anzeigen. Das Edit muss also immer Informiert werden, wenn sich die Ausgewählte Zeile des Grids ändert. Umgekehrt sollen änderungen des Textes des Edits sofort in das entsprechende Grid-Feld eingetragen werden, also muss das Grid auch vom Edit aus erreichbar sein.
Ich habe für dieses Beispiel folgenden Code erzeugt:Header des Edits:
#include <SysUtils.hpp> #include <Classes.hpp> #include <Controls.hpp> #include <StdCtrls.hpp> //--------------------------------------------------------------------------- class TEigenGrid; // Wird erst in der Implementierung includiert. class PACKAGE TEigenEdit : public TEdit { private: TEigenGrid* FGrid; protected: public: __fastcall TEigenEdit(TComponent* Owner); __published: __property TEigenGrid* Grid = {read = FGrid, write = FGrid}; }; //---------------------------------------------------------------------------Header des Grids:
#include <SysUtils.hpp> #include <Classes.hpp> #include <Controls.hpp> #include <Grids.hpp> //--------------------------------------------------------------------------- class TEigenEdit; // Wird erst in der Implementierung includiert. class PACKAGE TEigenGrid : public TStringGrid { private: TEigenEdit* FEdit; protected: public: __fastcall TEigenGrid(TComponent* Owner); __published: __property TEigenEdit* Edit = {read = FEdit, write = FEdit}; }; //---------------------------------------------------------------------------Beim Versuch das zu kompilieren meldet der Compiler: "E2109 Kein zulässiger Typ" und der Debugger steht auf der Zeile, in der die Property definiert wird.
Was mache ich falsch?
Gibt es grundsätzlich keine Möglichkeit Komponenten direkt miteinander kommunizieren zu lassen?
Bin ich gezwungen per Ereignis über das Form zu gehen und den Code für die Kommunikation zwischen den Komponenten bei jedem Form, das derartige Komponenten enthält per Copy & Paste zu reproduzieren?Gruß
Marc
-
Ich hatte sowas ähnliches auch mal gemacht und dort funktioniert das im Prinzip auch so, wie Du das
in Deinem Code machst. Der einzige Unterschied ist, dass meine beiden Klassen in einer Unit unter-
gebracht sind. Vielleicht muss bei Komponenten die Deklaration der Klasse bekannt sein, so dass
Forward-Deklarieren nicht funktioniert?
Auf welcher Eigenschaft wird denn eigentlich der Fehler angezeigt? Oder auf beiden?
Gruß,
Alexander
-
Der Fehler tritt prizipiell bei beiden Eigenschaften auf. Wo der Compiler meckert hängt von der Compile-Reihenfolge ab.
-
Dann mach doch für beide Komponenten Interfaces, also abstrakte Klassen, die ausschließlich aus Eigenschaften
und rein virtuellen Methoden bestehen. Dann hast Du zwei neue Header-Dateien, die Du jeweils per include hinzu-
nehmen kannst, ohne dass Du Probleme mit zirkulären includes bekommst.Gruß,
Alexander
-
Gute Idee. Das letzte Mal, als ich mich an Interfaces versucht habe, hat es allerdings nicht hingehauen.
Ich vermute man kann mit
dynamic_cast<Schnittstelle>(Objekt)ein Objekt in eine seiner Schnittstelle casten, oder?
(Zuletzt hatte ich es mit dem normalen
(Schnitstelle)Objektversucht.)
Gruß
Marc
-
Gerade ist mir aufgefallen, dass ich das Casten in die Schnittstelle für diesen Zweck ja gar nicht brauche.
Die Sache würde mich aber trotzdem interessieren. Ich fange mal einen neuen Thread an...
-
Mit Interface meinte ich so etwas:
class MeinInterface { public: virtual void tuDies() = 0; virtual int tuDas(bool WirklichTun, int SoOftTun) = 0; // Weitere rein virtuelle Methoden __property int Count = {read=getCount, write=setCount}; // und weitere Eigenschaften protected: virtual int getCount() = 0; virtual void setCount(int Value) = 0; };Der Header einer Implementierung könnte dann so aussehen:
#include "MeinInterface.h" #include "MeinInterface2.h" class MeineImplementierung: public MeinInterface { public: MeineImplementierung(); ~MeineImplementierung(); virtual void tuDies(); virtual int tuDas(bool WirklichTun, int SoOftTun); __property MeinInterface2* AnderesInterface = {read=FAnderesInterface, write=FAnderesInterface}; protected: virtual int getCount(); virtual void setCount(int Value); private: MeinInterface2* FAnderesInterface; };Gruß,
Alexander
-
Eine sehr schöne Idee. Leider funktioniert es nicht...
Mittlerweile habe ich es so weit eingekreist, dass der Compiler schon meckert (E2109 Kein zulässiger Typ), wenn man überhaupt versucht einen Pointer auf ein Interface als Typ für eine Property zu verwenden. (Also ohne irgendwelche über-Kreuz-Geschichten)Hat noch jemand eine Idee?
Gruß
Marc
-
MarcE schrieb:
Leider funktioniert es nicht...
Solche Aussagen liebe ich

MarcE schrieb:
Mittlerweile habe ich es so weit eingekreist, dass der Compiler schon meckert, wenn man überhaupt versucht einen Pointer auf ein Interface als Typ für eine Property zu verwenden.
Was genau hast Du denn gemacht?
Unter Umständen müssen Klassen, die Du über eine Eigenschaft verwenden willst von TObject erben?
Gruß,
Alexander
-
Unter Umständen müssen Klassen, die Du über eine Eigenschaft verwenden willst von TObject erben?
Tatsächlich, das war's! Ich find das könnt Borland an eine Stelle der Dokumentation schreiben, wo man es leicht findet...
Vielen Dank,
Marc
-
MarcE schrieb:
Ich find das könnt Borland an eine Stelle der Dokumentation schreiben, wo man es leicht findet...
Wo steht das denn?
Gruß,
Alexander
-
Nirgends, wo ich gesucht habe.
Im Übrigen zu früh gefreut: TObject ist nicht abstrakt. Die Property kompiliert so zwar, aber die resultierende Klasse ist keine Schnittstelle mehr.
-
Damit wären wir also wieder bei "E2109 Kein zulässiger Typ", und zwar mit folgenden Code:
__interface IZusatzfunktionalitaet { public: virtual void __fastcall MachWas() = 0; };#include "IZusatzfunktionalitaet.h" //--------------------------------------------------------------------------- class PACKAGE TEditPlus : public TEdit { private: IZusatzfunktionalitaet* FZusatz; protected: public: __fastcall TEditPlus(TComponent* Owner); __published: __property IZusatzfunktionalitaet* Zusatz = {read = FZusatz, write = FZusatz}; };
-
Nachdem ich jetzt noch mal ein bisschen rumprobiert habe, glaube ich, auf eine Lösung für das Problem
gekommen zu sein. Im Prinzip funktioniert meine Lösung so ähnlich, wie ich es schon mal angedeutet
hatte:
- Zuerst habe ich mir zwei abstrakte Komponenten definiert - jeweils ein Abkömmling von TEdit und TStringGrid
- Dann habe ich zwei konkrete Komponenten definiert, die von den ersten beiden erben und jeweils eine
Eigenschaft der abstrakten Komponente besitzen.Hier mal ein wenig Code:
//---------------------------------------- // MyAbstractComponents.h //---------------------------------------- #ifndef MyAbstractComponentsH #define MyAbstractComponentsH #include <SysUtils.hpp> #include <Classes.hpp> #include <Controls.hpp> #include <Grids.hpp> #include <StdCtrls.hpp> class PACKAGE TMyAbstractEdit : public TEdit { private: protected: __fastcall TMyAbstractEdit(TComponent* Owner); public: __published: }; class PACKAGE TMyAbstractStringGrid : public TStringGrid { private: protected: __fastcall TMyAbstractStringGrid(TComponent* Owner); public: __published: }; #endif //---------------------------------------- // MyAbstractComponents.cpp //---------------------------------------- #include <vcl.h> #pragma hdrstop #include "MyAbstractComponents.h" #pragma package(smart_init) __fastcall TMyAbstractEdit::TMyAbstractEdit(TComponent* Owner) : TEdit(Owner) { } __fastcall TMyAbstractStringGrid::TMyAbstractStringGrid(TComponent* Owner) : TStringGrid(Owner) { } //---------------------------------------- // MyEdit.h //---------------------------------------- #ifndef MyEditH #define MyEditH #include <SysUtils.hpp> #include <Classes.hpp> #include <Controls.hpp> #include <StdCtrls.hpp> #include <MyAbstractEdit.h> class PACKAGE TMyEdit : public TMyAbstractEdit { private: TMyAbstractStringGrid* FStringGrid; protected: public: __fastcall TMyEdit(TComponent* Owner); __published: __property TMyAbstractStringGrid* StringGrid = {read=FStringGrid, write=FStringGrid}; }; #endif //---------------------------------------- // MyEdit.cpp //---------------------------------------- #include <vcl.h> #pragma hdrstop #include "MyEdit.h" #pragma package(smart_init) static inline void ValidCtrCheck(TMyEdit *) { new TMyEdit(NULL); } __fastcall TMyEdit::TMyEdit(TComponent* Owner) : TMyAbstractEdit(Owner) { } namespace Myedit { void __fastcall PACKAGE Register() { TComponentClass classes[1] = {__classid(TMyEdit)}; RegisterComponents("Test", classes, 0); } } //---------------------------------------- // MyStringGrid.h //---------------------------------------- #ifndef MyStringGridH #define MyStringGridH #include <SysUtils.hpp> #include <Classes.hpp> #include <Controls.hpp> #include <MyAbstractEdit.h> class PACKAGE TMyStringGrid : public TMyAbstractStringGrid { private: TMyAbstractEdit* FEdit; protected: public: __fastcall TMyStringGrid(TComponent* Owner); __published: __property TMyAbstractEdit* Edit = {read=FEdit, write=FEdit}; }; #endif //---------------------------------------- // MyStringGrid.cpp //---------------------------------------- #include <vcl.h> #pragma hdrstop #include "MyStringGrid.h" #pragma package(smart_init) static inline void ValidCtrCheck(TMyStringGrid *) { new TMyStringGrid(NULL); } __fastcall TMyStringGrid::TMyStringGrid(TComponent* Owner) : TMyAbstractStringGrid(Owner) { } namespace Mystringgrid { void __fastcall PACKAGE Register() { TComponentClass classes[1] = {__classid(TMyStringGrid)}; RegisterComponents("Test", classes, 0); } }Das konnte ich bei mir kompilieren, installieren und auch verwenden.
Gruß,
Alexander
-
Ah, jetzt! Das tut. Vielen Dank!
Das Ganze funktioniert übrigens auch, wenn man die abstrakten Komponenten in einzelne Dateien packt.Gruß
MarcPS: Ich hatte (vergeblich) immer das versucht:
class MyAbstractEdit { public: ZusatzfunktionEdit() = 0; } class MyAbstractGrid { public: ZusatzfunktionGrid() = 0; } class MyEdit : public TEdit, public MyAbstractEdit { private: MyAbstractGrid* FGrid; public: ZusatzfunktionEdit(); __published: __property MyAbstractGrid* Grid = {read = FGrid, write = FGrid}; } class MyGrid : public TStringGrid, public MyAbstractGrid { private: MyAbstractEdit* FEdit; public: ZusatzfunktionGrid(); published: __property MyAbstractEdit* Edit = {read = FEdit, write = FEdit}; }