我想使用TOwnedCollection / TCollectionItem实现一个集合或列表。我需要一个具有多态性的类的持久列表(从FileStream加载和创建)。
到目前为止,这是我的代码(部分),但是我没有成功创建派生类TGenerator而不是它的父TPowerComponent并将其添加到Collection。
//-------------------------------------------------------------------------------------
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可以拥有一个或一些NetWork Collection的项目,而无需重新创建它们。
这可以通过以下方式完成
std::list<TPowerComponent*> SelectedComponents;
但我无法使用FileStream / persistent list编写/读取它们。我需要将它们放在TCollection中但不重新创建它们。
怎么样?
RTL的TCollection
对象的原生DFM流仅部分支持多态TCollectionItem
类。
您可以在代码中添加多态TCollectionItem
对象到TCollection
(在运行时,以及在设计时借助自定义编辑器),只要它们都派生自传递给TCollection
构造函数的公共基类。这样的集合甚至可以原样保存到DFM中。
但是,当加载DFM时,本机流将强制从DFM读取的所有集合项使用您传递给TCollectionItem
构造函数的任何TCollection
类类型。因此,无法在本机加载多态类。
覆盖该行为的唯一方法是禁用集合的本地流(使您的TCollection
属性为非published
,或至少将其标记为stored=false
),然后手动流式传输集合项。
让你的主要组件(或任何TPersistent
类拥有该集合)覆盖虚拟DefineProperties()
方法以调用TFiler.DefineProperty()
来注册用于流式传输集合项的自定义读/写方法。要支持多态类,您必须在写入其属性值之前将每个项的ClassName
写入DFM,然后再读取该名称,以便在读取属性值之前知道要实例化哪个类。