2017-12-28 3 views
0

Ich möchte eine Sammlung oder Liste mit TOwnedCollection/TCollectionItem implementieren. Ich brauche eine persistente Liste (um einen FileStream zu laden und zu erstellen) von Klassen mit Polymorphismus.Wie eine 2-mal abgeleitete Klasse von TCollectionItem zu TOwnedCollection hinzufügen?

Hier ist (Teil von) mein Code so weit, aber es ist mir nicht gelungen, die abgeleitete Klasse TGenerator anstelle seiner übergeordneten TPowerComponent zu erstellen und sie der Collection hinzuzufügen.

//------------------------------------------------------------------------------------- 
class TPCCollection : public TOwnedCollection 
    { 
      typedef TOwnedCollection inherited; 
    private: 
      TPowerComponent* __fastcall GetPowerComponent(int Index); 
      void __fastcall SetPowerComponent(int Index, TPowerComponent *Value); 

    public: 
      __fastcall TPCCollection(TPersistent *Owner); 

      HIDESBASE TPowerComponent* __fastcall Add(void); 
      HIDESBASE TPowerComponent* __fastcall Insert(int Index); 

      __property TPowerComponent* PCCollection[int Index] = {read=GetPowerComponent, write=SetPowerComponent}; 
}; 

//------------------------------------------------------------------------------------- 
class TPowerComponent : public TCollectionItem 
{ 
    typedef TCollectionItem inherited; 
public : 
    int X, Y, Rotation; 
    PowSymbType HisType; 

    __fastcall TPowerComponent(TCollection *Collection, PowSymbType AType); 
    void __fastcall Assign(TPersistent *Source); 
    virtual void __fastcall Paint(TCanvas * Canvas); 
}; 
//------------------------------------------------------------------------------------- 
class TGenerator : public TPowerComponent 
{ 
      typedef TPowerComponent inherited; 
public : 
    double PG, Qgmin, Qgmax, Vsch; 

    __fastcall TGenerator(TCollection *Collection, PowSymbType AType); 
    void __fastcall Assign(TPersistent *Source); 
    virtual void __fastcall Paint(TCanvas * Canvas);  
    }; 
//------------------------------------------------------------------------------------- 
// implementation 
//------------------------------------------------------------------------------------- 
// TPCCOllection 
//------------------------------------------------------------------------------------- 
__fastcall TPCCollection::TPCCollection(TPersistent *Owner) 
     : TOwnedCollection(Owner, __classid(TPowerComponent)) 
{ 
} 
//------------------------------------------------------------------------------------- 
TPowerComponent* __fastcall TPCCollection::Add() 
{ 
    return static_cast<TPowerComponent>(inherited::Add()); 
} 
//------------------------------------------------------------------------------------- 
TPowerComponent* __fastcall TPCCollection::Insert(int Index) 
{ 
    return static_cast<TPowerComponent>(inherited::Insert(Index)); 
} 
//------------------------------------------------------------------------------------- 
TPowerComponent* __fastcall TPCCollection::GetPowerComponent(int Index) 
{ 
    return static_cast<TPowerComponent>(inherited::GetItem(Index)); 
} 
//------------------------------------------------------------------------------------- 
void __fastcall TPCCollection::SetPowerComponent(int Index, TPowerComponent *Value) 
{ 
    inherited::SetItem(Index, Value); 
} 
//------------------------------------------------------------------------------------- 
// TPowerComponent 
//------------------------------------------------------------------------------------- 
__fastcall TPowerComponent::TPowerComponent(TCollection *Collection, PowSymbType AType) 
     : TCollectionItem(Collection) 
{ 
    HisType=AType; 
    Rotation=0; 
} 
//------------------------------------------------------------------------------------- 
void __fastcall TPowerComponent::Assign(TPersistent *Source) 
{ 
    TPowerComponent *Src = dynamic_cast<TPowerComponent>(Source); 
    if(Src) 
     { 
       // copy members from Src... 
     } 
    else inherited::Assign(Source); 
} 
//------------------------------------------------------------------------------------- 
// se dessine 
void __fastcall TPowerComponent::Paint(TCanvas * Canvas) 
{ 
... 
} 
//------------------------------------------------------------------------------------- 
// TGenerator 
//------------------------------------------------------------------------------------- 
__fastcall TGenerator::TGenerator(TCollection *Collection, PowSymbType AType) 
     :TPowerComponent(Collection, AType) 
{ 
    PG=0; Qgmin=0; Qgmax=0; Vsch=1.0; Con=-1; 
} 
//------------------------------------------------------------------------------------- 
void __fastcall TGenerator::Assign(TPersistent *Source) 
{ 
    TGenerator *Src = dynamic_cast<TGenerator>(Source); 
    if(Src) 
     { 
       // copy members from Src... 
     } 
    else inherited::Assign(Source); 
} 



//------------------------------------------------------------------------------------- 
// Usage 
TPCCollection * NetWork = new TPCCollection(this); 

// Usage to Access all the collection 
for(int i=0; i< NetWork->Count; i++) 
    { 
    ((TPowerComponent*)(NetWork->Items[i]))->Paint(Canvas); 
    } 

Um einen TGenerator hinzufügen und kein TPowerComponent, ich benutze:

TGenerator * Gen=new TGenerator(NetWork, Generator); 

Die Schaffung des TCollectionItem Kind sich automatisch auf die

Das Problem hier

TCollection hinzuzufügen, ist, dass wir‘ t den Prozess der Artikelerstellung vom Hinzufügen zur Sammlung trennen.

Wenn ich eine andere Liste benötige, die einige Elemente der ersten Auflistungsliste enthalten kann, können SelectedComponents beispielsweise einen oder einige Elemente der NetWork Collection enthalten, ohne sie neu erstellen zu müssen.

kann dies mit

std::list<TPowerComponent*> SelectedComponents; 

getan werden, aber ich kann sie mit Filestream/persistent Liste nicht schreiben/lesen. Ich muss sie in eine TCollection einfügen, aber ohne sie neu zu erstellen.

Wie?

+0

Ich habe meine Frage bearbeitet, um Moderator Empfehlung zu erfüllen – Lotfi

Antwort

1

Das native DFM-Streaming des RTL für TCollection-Objekte unterstützt nur teilweise polymorphe TCollectionItem-Klassen.

Sie können in Code zu einem TCollection polymorphen TCollectionItem Objekte hinzufügen (zur Laufzeit, sowie zur Design-Zeit mit Hilfe eines benutzerdefinierten Editor), solange sie alle von einer gemeinsamen Basisklasse ableiten, die übergeben wird der TCollection Konstruktor. Und solch eine Sammlung kann sogar so wie sie ist in einem DFM gespeichert werden.

Beim Zurückladen eines DFMs wird jedoch beim nativen Streaming alle vom DFM gelesenen Sammlungselemente auf den Klassen-Typ TCollectionItem gesetzt, den Sie an den TCollection-Konstruktor übergeben. Daher können polymorphe Klassen nicht nativ geladen werden.

Der einzige Weg, um dieses Verhalten zu überschreiben stammt Streaming für die Sammlung deaktivieren (machen Sie Ihre TCollection Eigenschaft published oder zumindest markieren Sie ihn als stored=false nicht sein), und dann die manuell Kollektionsteile streamen.

Haben Sie Ihre Hauptkomponente (oder was auch immer TPersistent Klasse besitzt die Sammlung) außer Kraft setzt die virtuelle DefineProperties() Methode TFiler.DefineProperty() rief für das Streaming der Kollektionsteile individuellen Lesen/Schreiben Methoden zu registrieren. Um polymorphe Klassen zu unterstützen, müssen Sie die ClassName jedes Elements in den DFM schreiben, bevor Sie die Eigenschaftswerte schreiben. Lesen Sie dann den Namen zurück, damit Sie wissen, welche Klasse vor dem Lesen der Eigenschaftswerte instanziiert werden soll.

+0

Meine TPowerComponent und ihre Kinder sind nicht Teil eines TForm wie Tbuttons oder ... also wenn ich Sie verstehe, brauche ich nicht einmal eine TCollection/TCollectionItem Klassen zu behandeln Sie? und schreibe sie in einen Stream?aber wie, wenn ich das Objekt aus dem Stream (manuell) lese, kann ich herausfinden, welches Kind es ist (TGenerator, TLoad, TLIne ...)? – Lotfi

+1

Sie müssen 'TCollection' /' TCollectionItem' nicht verwenden, es sei denn, Sie möchten die Entwurfszeitbearbeitung oder das DFM-Streaming unterstützen. Wie beim Streamen müssen Sie, wie ich in meiner Antwort gesagt habe, den Namen eines Kind-Klassentyps in den Stream schreiben, bevor Sie seine Werte schreiben. Wenn Sie den Stream zurückgelesen haben, müssen Sie zuerst den Namen eines Kindtyps lesen, um zu wissen, welche Klasse für das Kind vor dem Lesen der Werte zuerst instanziiert werden soll. –

Verwandte Themen