[英]Use DefineProperties to replace TPersistent properties e.g. TFont
I'm updating some properties in a component. 我正在更新组件中的某些属性。 In order to avoid missing property errors I'm using DefineProperties to read the old properties from the stream. 为了避免丢失属性错误,我正在使用DefineProperties从流中读取旧属性。 Most properties work fine eg Integer , but I can't get properties based on TPersistent to work. 大多数属性都可以正常工作,例如Integer ,但是我无法基于TPersistent获得属性。 The ReadProperty(TPersistent) procedure in TReader is protected, not public and requires a hack to access it. 在行者的读属性(TPersistent)程序的保护,不公开,需要一个黑客来访问它。 Even then, the ReadFontProperty procedure is never called and the missing property exception occurs. 即使这样,也永远不会调用ReadFontProperty过程,并且会发生缺少的属性异常。
How do I read the TFont property? 如何阅读TFont属性?
Here's some sample code of how I'm trying to do it. 这是一些有关我如何尝试的示例代码。
...
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;
...
Update 1 更新1
Tried David's suggestion using the following code: 使用以下代码尝试了David的建议:
Filer.DefineProperty('Font.CharSet', ReadFontCharSet, nil, False);
... ...
procedure TMyComponent.ReadFontCharSet(Reader: TReader);
begin
Reader.ReadInteger;
end;
I get an Invalid Property Value error. 我收到无效的属性值错误。 I guess it's something to do with Charset being of type TFontCharset (= System.UITypes.TFontCharset = 0..255). 我想这与Charset类型为TFontCharset (= System.UITypes.TFontCharset = 0..255)有关。 How do I read this type of property? 我如何阅读这种类型的财产?
In order to do this you need to work with each individual published property of TFont
and you will need to use fully qualified names. 为此,您需要使用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
etc. should read the old property values into the newly named component. ReadFontName
, ReadFontHeight
等应将旧的属性值读入新命名的组件中。
procedure TMyComponent.ReadFontName(Reader: TReader);
begin
FNewFontProperty.Name := Reader.ReadString;
end;
// etc. etc.
Update 更新资料
You ask how to read the Charset property. 您询问如何读取Charset属性。 This is complex because it can be written either as a textual identifier (see the FontCharsets
constant in Graphics.pas), or as a plain integer value. 这很复杂,因为它既可以写为文本标识符(请参见Graphics.pas中的FontCharsets
常量),也可以写为纯整数值。 Here is some rapidly hacked together code that will read your Charset. 这是一些快速被黑客入侵的代码,它们将读取您的Charset。
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;
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.