【问题标题】:How to add a 2-times derived class of TCollectionItem to TOwnedCollection?如何将 TCollectionItem 的 2 次派生类添加到 TOwnedCollection?
【发布时间】:2018-06-09 05:10:18
【问题描述】:

我想使用 TOwnedCollection / TCollectionItem 实现一个集合或列表。我需要一个具有多态性的类的持久列表(从 FileStream 加载和创建)。

到目前为止,这是我的(部分)代码,但我没有成功创建派生类 TGenerator 而不是其父类 TPowerComponent 并将其添加到集合中。

//-------------------------------------------------------------------------------------
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);
    }

要添加 TGenerator 而不是 TPowerComponent,我使用:

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

创建 TCollectionItem 子项会自动将自身添加到 TCollection

这里的问题是我们无法将创建项目的过程与将其添加到集合中分开。

当我需要另一个可以包含第一个集合列表的某些项目的列表时,例如,SelectedComponents 可以包含网络集合的一个或一些项目,而无需重新创建它们。

这可以通过

std::list<TPowerComponent*> SelectedComponents;

但我无法使用 FileStream / 持久列表写入/读取它们。我需要将它们放在 TCollection 中,但不需要重新创建它们。

怎么做?

【问题讨论】:

  • 我编辑了我的问题以满足版主的建议

标签: c++builder vcl tcollectionitem townedcollection


【解决方案1】:

TCollection 对象的 RTL 原生 DFM 流仅部分支持多态 TCollectionItem 类。

您可以在代码中将多态TCollectionItem 对象添加到TCollection(在运行时,以及在自定义编辑器的帮助下在设计时),只要它们都派生自一个公共基类传递给TCollection 构造函数。这样的集合甚至可以按原样保存到 DFM。

但是,当加载回 DFM 时,本机流式传输将强制从 DFM 读取的所有集合项使用您传递给 TCollection 构造函数的任何 TCollectionItem 类类型。所以,不能原生加载多态类。

覆盖该行为的唯一方法是禁用集合的本机流式传输(使您的TCollection 属性为非published,或至少将其标记为stored=false),然后手动流式传输集合项.

让您的主要组件(或任何TPersistent 类拥有该集合)覆盖虚拟DefineProperties() 方法以调用TFiler.DefineProperty() 以注册自定义读取/写入方法以流式传输集合项。要支持多态类,您必须先将每个项目的 ClassName 写入 DFM,然后再写入其属性值,然后读回名称,以便在读取属性值之前知道要实例化哪个类。

【讨论】:

  • 我的 TPowerComponent 和他们的孩子不应该是 TForm 的一部分,比如 Tbuttons 或者......所以如果我理解你,我什至不需要 TCollection/TCollectionItem 类来处理它们?并将它们写在流上?但是当我(手动)从 Stream 中读取对象时,我如何才能确定它是哪个子对象(TGenerator、TLoad、TLine...)?
  • 您不需要使用TCollection/TCollectionItem,除非您想支持设计时编辑或 DFM 流。至于流式传输,正如我在回答中所说,您必须先将孩子的类类型名称写入流,然后再写入它的值。当你读回流时,你必须先读取一个孩子的类类型名称,以知道要为孩子实例化哪个类,然后再读取它的值。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2019-02-17
相关资源
最近更新 更多