我想在组件中使用float属性,但将其设置为一些非零的默认值(假设它是1000.0)。如果我尝试在Create中执行此操作,则该属性开始表现异常,因为默认值将其浮动为0(请参见classes.TWriter.WriteProperty.WriteFloatProp.IsDefaultValue),因此当我在表单设计人员,delphi不会保存该值(在这种情况下为默认值),但是当下次加载组件时,我的Create会将其设置为1000.0,因此实际上我具有我未设置的值。
问题是无法用'default'指令设置默认值(编译器说'默认值必须是序数,指针或小集合类型'),并且也无法强制使用存储的指令,它不起作用(Delphi 5)
所以有机会找到解决方法吗?
谢谢,
最大
也许您可以使用stored
指令:
property MyFloat: Float read GetValue write SetValue stored IsMyFloatStored;
具有返回True且MyFloat的布尔函数IsMyFloatStored
没有其默认值。
我通过在TPersistent的后代中实现DefineProperties方法来解决此问题。我想为这个问题提供一个通用的解决方案,以便可以在所有对象中轻松实现所有相关属性。外观如下:
TOverridePropFiler = class
private
FReadWritePropName: string;
FObject: TObject;
procedure ReadOverrideProp(Reader: TReader);
procedure WriteOverrideProp(Writer: TWriter);
public
constructor Create(Filer:TFiler; Obj:TObject; Name:string);
end;
{ TOverridePropFiler }
constructor TOverridePropFiler.Create(Filer:TFiler; Obj:TObject; Name:string);
begin
FReadWritePropName:=Name;
FObject:=obj;
if (Name='') or not Assigned(GetPropInfo(Obj,Name)) then
Raise Exception.CreateFmt('Property %s not found in object %s',[Name,Obj.ClassName]);
Filer.DefineProperty(Name, ReadOverrideProp, WriteOverrideProp,
GetPropValue(FObject,FReadWritePropName,False)<>uiFloat);
end;
procedure TOverridePropFiler.ReadOverrideProp(Reader: TReader);
begin
SetPropValue(FObject,FReadWritePropName,Reader.ReadFloat);
end;
procedure TOverridePropFiler.WriteOverrideProp(Writer: TWriter);
begin
Writer.WriteDouble(GetPropValue(FObject,FReadWritePropName,False));
end;
我在我的DefineProperties方法中按如下方式调用它:
procedure TMyObj.DefineProperties(Filer: TFiler);
begin
inherited;
TOverridePropFiler.Create(Filer,Self,'dTOverride').Free;
end;
为了对此进行概括,我不得不使用RTTI并在本地保存属性名称(无法从TWriter中删除它,并且需要对TReader进行破解)。为了使其线程安全(并且因为TFiler.DefineProperty需要“对象”功能),我将整个对象封装在一个对象中。
就我而言,我希望默认值为uiFloat。该常数可以设置为您想要的任何值。如果要为不同的属性使用不同的默认值,则可以轻松地将默认值作为参数添加到“创建”函数中。
请注意,您仍然必须将属性设置为TMyObj的构造函数中的默认值。
在我看来,这是解决Delphi中相当严重的限制的一种非常有效的方法。
编辑:您需要记住要在所有使用此属性的属性中添加“ false”。
如编译器所说,浮点值不能具有默认值。我唯一能想到的就是将浮点值存储在标度整数中。例如,如果只需要yourFloat
的三个小数,则可以存储yourInt = 1000 * yourFloat
。然后默认值为yourInt := 1000000
,对应于yourFloat := 1000.000
。
当然,您可以更优雅地进行此操作,例如
private
FMyFloat: real;
function GetValue: integer;
procedure SetValue(Value: integer);
published
property MyInteger: integer read GetValue write SetValue default 1000000;
implementation
function TMyClass.GetValue: integer;
begin
result := round(1000 * FMyFloat);
end;
procedure TMyClass.SetValue(Value: integer);
begin
FMyFloat := Value / 1000;
end;
这样,您仍然只能从类本身内部看到浮点字段FMyFloat
。但是该属性将是一个可缩放的整数,因此可以很好地存储。
默认值实际上仅告诉流代码默认值是什么,如果是默认值,则不进行流传输。这省去了流式传输所有默认值的麻烦。无论如何,该组件实际上必须在.Create中设置默认值。编译器没有任何魔力为您设置默认值。
在这种情况下,没有关系,因为您可以在.Create构造函数中设置默认值,然后在定义中保留默认值。该值将始终存储,但是将根据需要运行。
只是遇到了这个问题,并通过在构造函数中将我想要的值设置为默认值并对该属性使用nodefault指令来解决了该问题。