【问题标题】:Use DefineProperties to replace TPersistent properties e.g. TFont使用 DefineProperties 替换 TPersistent 属性,例如字体
【发布时间】:2012-07-02 16:11:54
【问题描述】:

我正在更新组件中的一些属性。为了避免丢失属性错误,我使用 DefineProperties 从流中读取旧属性。大多数属性都可以正常工作,例如整数,但我无法让基于 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);

...

procedure TMyComponent.ReadFontCharSet(Reader: TReader);
begin
  Reader.ReadInteger;
end;

我收到 无效的属性值 错误。我想这与 Charset 的类型为 TFontCharset (= System.UITypes.TFontCharset = 0..255)有关。如何读取此类属性?

【问题讨论】:

    标签: delphi properties delphi-xe2


    【解决方案1】:

    为此,您需要使用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
    

    ReadFontNameReadFontHeight 等应该将旧的属性值读入新命名的组件中。

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

    更新

    您询问如何读取 Charset 属性。这很复杂,因为它既可以写为文本标识符(参见 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;
    

    【讨论】:

    • @norgepaul 你是怎么做到的?我很确定这是您问题的答案。
    • 嗨,大卫。感谢您的回答。我确定它是正确的,但我还没有机会测试它。我会尽快解决的。
    • 好的,我只是想知道您是否遇到了问题并且很好奇。
    • 尝试添加 CharSet 属性,但收到“无效属性值”错误。我已经用更多信息更新了这个问题。
    • 是否需要读取Charset属性的值,还是跳过也可以。您可以通过从ReadFontCharSet 调用Reader.SkipValue 来跳过它。虽然它是一个字符串或一个整数,但阅读它有点棘手。没那么棘手。
    猜你喜欢
    • 2016-12-27
    • 2015-10-11
    • 2022-10-12
    • 1970-01-01
    • 1970-01-01
    • 2015-06-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多