Delphi 使用定义属性替换t持久属性,例如TFont

Delphi 使用定义属性替换t持久属性,例如TFont,delphi,properties,delphi-xe2,Delphi,Properties,Delphi Xe2,我正在更新组件中的一些属性。为了避免丢失属性错误,我使用DefineProperties从流中读取旧属性。大多数属性都可以正常工作,例如Integer,但我无法基于TPersistent使属性正常工作。TReader中的ReadProperty(TPersistent)过程受保护,不公开,需要黑客才能访问。即使如此,也不会调用ReadFontProperty过程,并且会发生缺少的属性异常 如何读取TFont属性 下面是一些示例代码,说明我是如何做到这一点的 ... type TMyComp

我正在更新组件中的一些属性。为了避免丢失属性错误,我使用DefineProperties从流中读取旧属性。大多数属性都可以正常工作,例如Integer,但我无法基于TPersistent使属性正常工作。TReader中的ReadProperty(TPersistent)过程受保护,不公开,需要黑客才能访问。即使如此,也不会调用ReadFontProperty过程,并且会发生缺少的属性异常

如何读取TFont属性

下面是一些示例代码,说明我是如何做到这一点的

...

type
  TMyComponent = class(TComponent)
  strict private
    // Removed 
    //FIntegerProperty: Integer;
    //FFontProperty: TFont;

    // New
    FNewIntegerProperty: Integer;
    FNewFontProperty: TFont;

    procedure ReadIntegerProperty(Reader: TReader);
    procedure ReadFontProperty(Reader: TReader);
  protected
    procedure DefineProperties(Filer: TFiler); override;
  published
    // Removed properties
    //property IntegerProperty: Integer read FIntegerProperty write FIntegerProperty;
    //property FontProperty: TFont read FFontProperty write SetFontProperty;

    // New properties
    property NewIntegerProperty: Integer read FNewIntegerProperty write FNewIntegerProperty;
    property NewFontProperty: TFont read FNewFontProperty write SetNewFontProperty;
  end;

implementation

procedure TMyComponent.DefineProperties(Filer: TFiler);
begin
  inherited;

  // This works
  Filer.DefineProperty('IntegerProperty', ReadIntegerProperty, nil, FALSE);

  // This doesn't
  Filer.DefineProperty('FontProperty', ReadFontProperty, nil, FALSE);
end;

procedure TMyComponent.ReadIntegerProperty(Reader: TReader);
begin
  FNewIntegerProperty:= Reader.ReadInteger;
end;

type
  THackReader = class(TReader);

procedure TMyComponent.ReadFontProperty(Reader: TReader);
begin
  { TODO : This doesn't work. How do we read fonts? }
  THackReader(Reader).ReadProperty(FNewFontProperty);
end;

...
更新1

使用以下代码尝试了David的建议:

Filer.DefineProperty('Font.CharSet', ReadFontCharSet, nil, False);


我得到一个无效的属性值错误。我想这与字符集的类型TFontCharset(=System.UITypes.TFontCharset=0..255)有关。如何读取此类型的属性?

要执行此操作,您需要使用
TFont
的每个已发布属性,并且需要使用完全限定名

Filer.DefineProperty('FontProperty.Name', ReadFontName, nil, False);
Filer.DefineProperty('FontProperty.Height', ReadFontHeight, nil, False);
Filer.DefineProperty('FontProperty.Size', ReadFontSize, nil, False);
// and so on for all the other published properties of TFont
ReadFontName
ReadFontHeight
等应将旧属性值读入新命名的组件中

procedure TMyComponent.ReadFontName(Reader: TReader);
begin
  FNewFontProperty.Name := Reader.ReadString;
end;

// etc. etc.
更新

您询问如何读取字符集属性。这很复杂,因为它既可以作为文本标识符写入(请参见Graphics.pas中的
FontCharsets
常量),也可以作为纯整数值写入。下面是一些快速拼凑起来的代码,可以读取您的字符集

procedure TMyComponent.ReadFontCharset(Reader: TReader);

  function ReadIdent: string;
  var
    L: Byte;
    LResult: AnsiString;
  begin
    Reader.Read(L, SizeOf(Byte));
    SetString(LResult, PAnsiChar(nil), L);
    Reader.Read(LResult[1], L);
    Result := UTF8ToString(LResult);
  end;

  function ReadInt8: Shortint;
  begin
    Reader.Read(Result, SizeOf(Result));
  end;

  function ReadInt16: Smallint;
  begin
    Reader.Read(Result, SizeOf(Result));
  end;

var
  Ident: string;
  CharsetOrdinal: Integer;

begin
  Beep;
  case Reader.ReadValue of
  vaIdent:
    begin
      Ident := ReadIdent;
      if not IdentToCharset(Ident, CharsetOrdinal) then begin
        raise EReadError.Create('Could not read MyFont.Charset');
      end;
      FNewFontProperty.Charset := CharsetOrdinal;
    end;
  vaInt8:
    FNewFontProperty.Charset := ReadInt8;
  vaInt16:
    FNewFontProperty.Charset := ReadInt16;
  else
    raise EReadError.Create('Could not read FontProperty.Charset');
  end;
end;

@诺格保罗,你是怎么做到的?我很确定这就是你问题的答案。嗨,大卫。谢谢你的回答。我确信它是正确的,但我还没有机会测试它。我会尽快开始。好的,我只是想知道您是否遇到了问题,并对此感到好奇。尝试添加CharSet属性,但出现了“Invalid property value”错误。我已经用更多信息更新了问题。您需要读取
字符集
属性的值,还是可以跳过它。您可以从
ReadFontCharSet
调用
Reader.SkipValue
跳过它。但是读起来有点棘手,因为它不是字符串就是整数。注意,没那么棘手。
procedure TMyComponent.ReadFontCharset(Reader: TReader);

  function ReadIdent: string;
  var
    L: Byte;
    LResult: AnsiString;
  begin
    Reader.Read(L, SizeOf(Byte));
    SetString(LResult, PAnsiChar(nil), L);
    Reader.Read(LResult[1], L);
    Result := UTF8ToString(LResult);
  end;

  function ReadInt8: Shortint;
  begin
    Reader.Read(Result, SizeOf(Result));
  end;

  function ReadInt16: Smallint;
  begin
    Reader.Read(Result, SizeOf(Result));
  end;

var
  Ident: string;
  CharsetOrdinal: Integer;

begin
  Beep;
  case Reader.ReadValue of
  vaIdent:
    begin
      Ident := ReadIdent;
      if not IdentToCharset(Ident, CharsetOrdinal) then begin
        raise EReadError.Create('Could not read MyFont.Charset');
      end;
      FNewFontProperty.Charset := CharsetOrdinal;
    end;
  vaInt8:
    FNewFontProperty.Charset := ReadInt8;
  vaInt16:
    FNewFontProperty.Charset := ReadInt16;
  else
    raise EReadError.Create('Could not read FontProperty.Charset');
  end;
end;