浮点属性非零默认值,有可能吗?

Posted

技术标签:

【中文标题】浮点属性非零默认值,有可能吗?【英文标题】:Float property non-zero default, is it possible? 【发布时间】:2011-04-28 01:56:03 【问题描述】:

我想在我的组件中使用浮点属性,但将其设置为某个非零默认值(假设它是 1000.0)。如果我尝试在 Create 中执行此操作,则该属性开始表现得很疯狂,因为它的默认值浮动为 0(请参阅 classes.TWriter.WriteProperty.WriteFloatProp.IsDefaultValue)所以当我用0 在表单设计器中,delphi 不保存这个值(在这种情况下是默认值),但是我的 Create 会在下次加载组件时将它设置为 1000.0,所以实际上我有我没有的值放。

问题是没有办法用'default'指令设置默认值(编译器说'默认值必须是序数,指针或小集合类型'),这也是不可能的强制使用存储指令进行存储,它不起作用(Delphi 5)

那么有机会找到解决方法吗?

谢谢,

最大

【问题讨论】:

我对这个问题的解决方案也很感兴趣。你有想过解决办法吗? 【参考方案1】:

也许你可以使用stored 指令:

property MyFloat: Float read GetValue write SetValue stored IsMyFloatStored;

如果 MyFloat 没有其默认值,则返回 True 的布尔函数 IsMyFloatStored

【讨论】:

Ulrich,我希望它会有所帮助,但看起来存储过滤器在默认值处理之前工作,因此它不能用于覆盖默认比较处理【参考方案2】:

我通过在我的 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 进行 hack)。为了使其线程安全(并且因为 TFiler.DefineProperty 需要“对象”函数),我将整个东西封装在一个对象中。

就我而言,我希望默认值为 uiFloat。这个常数可以设置为任何你想要的。如果您想为不同的属性设置不同的默认值,您可以轻松地将默认值作为参数添加到 Create 函数中。

请注意,您仍然需要在 TMyObj 的构造函数中将属性设置为默认值。

在我看来,这是解决 Delphi 中一个相当严重的限制的一种相当有效的方法。

编辑:您需要记住将“stored false”添加到所有使用它的属性。

【讨论】:

【参考方案3】:

刚刚遇到这个问题,并通过在构造函数中将我想要的值设置为默认值并对该属性使用 nodefault 指令来解决它。

【讨论】:

【参考方案4】:

正如编译器所说,浮点值不能有默认值。我唯一能想到的是将浮点值存储在一个缩放的整数中。例如,如果您只需要三位小数的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。但该属性将是一个缩放整数,因此可以完美存储。

【讨论】:

谢谢,但不幸的是它在设计器中应该表现得像浮动。只是认为字符串属性(只接受格式正确的浮点数)可能是另一种选择【参考方案5】:

默认值实际上只是告诉流代码默认值是什么,如果是那个值,那么它就不会被流式传输。这样就不必流式传输所有默认值。组件实际上必须在 .Create 中设置默认值。编译器不会为您设置默认值。

在这种情况下,这无关紧要,因为您可以在 .Create 构造函数中设置默认值,然后在定义中省略默认值。该值将始终被存储,但它会按照您的意愿工作。

【讨论】:

不,VCL 的实际代码违背了我的意图。看,如果您将浮点值更改为 0,则该值将不会被流式传输。在这种情况下,我在 Create 中设置的属性没有被覆盖。换句话说,我的手(当我按下 Enter 键时)想要将某个值更改为零,但是当表单加载时,它将返回到我的非零默认值(因为没有流式传输)。

以上是关于浮点属性非零默认值,有可能吗?的主要内容,如果未能解决你的问题,请参考以下文章

组件的默认属性值

具有默认值的自动属性[重复]

JavaScriptSerializer 可以排除具有空值/默认值的属性吗?

自动属性默认值 [重复]

CloudKit 和 CoreData 默认值

自动属性值和默认值 [重复]