如何在C++Builder 1中从旧DFM流读取TBitmap到TPicture属性
解决C++Builder 1中TGlyph兼容旧DFM Bitmap属性的问题
核心问题分析
DFM流读取是层级式的:当遇到Glyph.Bitmap.Data时,会先尝试获取TGlyph的Bitmap属性对象,再读取该对象的Data子属性。直接删除Bitmap属性会导致流找不到该属性,触发“Property does not exist”错误。
解决方案步骤
1. 定义占位类处理Data属性读取
创建一个仅负责读取Data属性的占位类,将读取到的位图数据转换为TPicture:
class TBmpReader : public TObject { private: TGlyph* FGlyph; void __fastcall ReadData(TReader* Reader); public: __fastcall TBmpReader(TGlyph* AGlyph) : FGlyph(AGlyph) {} void __fastcall DefineProperties(Filer* Filer); }; void __fastcall TBmpReader::DefineProperties(Filer* Filer) { TObject::DefineProperties(Filer); // 仅定义读取回调,不提供写入,避免保存DFM时生成Data属性 Filer->DefineProperty("Data", ReadData, NULL, true); } void __fastcall TBmpReader::ReadData(TReader* Reader) { // 读取DFM中Bitmap.Data的32位长度字段 DWORD DataLen = Reader->ReadInteger(); TMemoryStream* MS = new TMemoryStream(); try { // 读取完整的位图数据(含BITMAPFILEHEADER) MS->CopyFrom(Reader->Stream, DataLen); MS->Position = 0; TBitmap* Bmp = new TBitmap(); try { // 加载位图数据到TBitmap,再赋值给TGlyph的Picture属性 Bmp->LoadFromStream(MS); FGlyph->Picture->Assign(Bmp); } __finally { delete Bmp; } } __finally { delete MS; } }
2. 修改TGlyph类,保留Bitmap伪属性
在TGlyph中保留一个只读的Bitmap属性(返回占位类实例),同时移除原Bitmap字段,新增Picture属性:
class TGlyph : public TObject { private: TPicture* FPicture; TBmpReader* FBitmapReader; TBmpReader* __fastcall GetBitmap(); void __fastcall SetPicture(TPicture* Value); public: __fastcall TGlyph(TComponent* AOwner); __fastcall ~TGlyph(); // 新的Picture属性,用于存储和读写位图 __property TPicture* Picture = {read=FPicture, write=SetPicture}; // 只读的Bitmap伪属性,仅用于兼容旧DFM读取 __property TBmpReader* Bitmap = {read=GetBitmap}; void __fastcall DefineProperties(Filer* Filer); }; __fastcall TGlyph::TGlyph(TComponent* AOwner) : TObject(AOwner) { FPicture = new TPicture(); FBitmapReader = new TBmpReader(this); } __fastcall TGlyph::~TGlyph() { delete FBitmapReader; delete FPicture; } TBmpReader* __fastcall TGlyph::GetBitmap() { return FBitmapReader; } void __fastcall TGlyph::SetPicture(TPicture* Value) { FPicture->Assign(Value); } void __fastcall TGlyph::DefineProperties(Filer* Filer) { TObject::DefineProperties(Filer); // 定义Picture属性的读写,保存DFM时仅输出Picture Filer->DefineProperty("Picture", [this](TReader* Reader) { FPicture->ReadState(Reader); }, [this](TWriter* Writer) { FPicture->WriteState(Writer); }, true); // 不定义Bitmap属性的写入回调,保存时不会生成Bitmap相关代码 }
关键说明
- 占位类的作用:让DFM流能找到
Bitmap属性对象,进而读取Data子属性,完成旧数据的迁移。 - 只读属性的意义:
Bitmap属性仅提供读取方法,没有写入逻辑,因此保存新DFM时不会生成Bitmap相关的代码,彻底废弃旧属性。 - 数据迁移逻辑:读取旧
Data数据后,直接转换为TBitmap并赋值给Picture,实现无缝兼容。
内容的提问来源于stack exchange,提问作者Martin Nijhoff
相关产品推荐
相关产品推荐

