Свойство с плавающей точкой ненулевое значение по умолчанию, возможно ли это? - PullRequest
4 голосов
/ 20 октября 2010

Я хотел бы использовать свойство float в моем компоненте, но установить для него ненулевое значение по умолчанию (скажем, оно равно 1000.0). Если я пытаюсь сделать это в Create, свойство начинает вести себя дико, поскольку значение по умолчанию для float его 0 (см. classes.TWriter.WriteProperty.WriteFloatProp.IsDefaultValue ), поэтому, когда я переопределяю некоторое значение с 0 в конструкторе форм delphi не сохраняет это значение (в данном случае это значение по умолчанию), но мой Create установит его на 1000.0, когда компонент будет загружен в следующий раз, так что на самом деле у меня есть значение, которое я не устанавливал ,

Проблема в том, что нет способа установить значение по умолчанию с помощью директивы default (компилятор говорит: Значения по умолчанию должны быть порядкового, указательного или малого типа набора '), а также невозможно принудительное хранение с сохраненной директивой, это не работает (Delphi 5)

Так есть ли шанс найти обходной путь?

Спасибо

Макс

Ответы [ 4 ]

1 голос
/ 26 октября 2011

Я исправил это, реализовав метод DefineProperties в моем потомке TPersistent. Я хотел сделать общее решение этой проблемы, которое я мог бы легко реализовать во всех моих объектах для всех соответствующих свойств. Вот как это выглядит:

  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. Эта константа может быть установлена ​​на то, что вы хотите. Если вам нужны разные значения по умолчанию для разных свойств, вы можете легко добавить значение по умолчанию в качестве параметра в функцию Create.

Обратите внимание, что в конструкторе TMyObj все еще необходимо установить свойство по умолчанию.

Мне кажется, это довольно эффективный способ обойти довольно серьезное ограничение в Delphi.

Редактировать: Вы должны помнить, чтобы добавить «сохраненное ложное» во все свойства, которые используют это.

1 голос
/ 20 октября 2010

Возможно, вы можете использовать директиву stored:

property MyFloat: Float read GetValue write SetValue stored IsMyFloatStored;

с логической функцией IsMyFloatStored, которая возвращает True, если MyFloat не имеет значения по умолчанию.

0 голосов
/ 20 октября 2010

Значение по умолчанию на самом деле только сообщает коду потока, что является значением по умолчанию, и если оно является этим значением, то оно не передается в потоке.Это избавляет от необходимости передавать все значения по умолчанию.Компонент должен фактически установить значение по умолчанию в .Create в любом случае.Компилятор не делает никакой магии, чтобы установить для вас значение по умолчанию.

В этом случае это не имеет значения, так как вы можете установить значение по умолчанию в конструкторе .Create, а затем просто оставить значение по умолчанию вОпределение.Значение всегда будет сохранено, но оно будет работать так, как вы хотите.

0 голосов
/ 20 октября 2010

Как говорит компилятор, значения с плавающей точкой не могут иметь значения по умолчанию.Единственное, о чем я могу думать, это сохранить значение с плавающей запятой в масштабированном целом числе.Например, если вам нужно только три десятичных знака 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 внутри самого класса.Но свойство будет масштабированным целым числом и, следовательно, может быть сохранено.

...