You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.12 09:23:15