Конференция "Компоненты" » Не сохраняется свойство
 
  • atruhin © (23.12.06 17:09) [0]
    В объекте есть свойство:
    property  ooFolderID : int64 read fFolderID write SetFolderID default -1;
    Но данное свойство при значении -1 сохраняется а при 0 нет, т.е. default -1 не действует!
    Где проблемма? Может как то связанно с типом In64?
  • Piroxyline © (24.12.06 12:37) [1]
    Были такие же траблы. Разбираться не стал, просто в конструкторе явно объявил значение.
  • Наиль © (25.12.06 07:25) [2]
    Для простых случаев - default.
    Для сложных - stored (примеры в генофонде)
    В данном случае используй [1].
  • atruhin © (25.12.06 16:41) [3]
    > В данном случае используй [1].

    Речь не об этом. В том то и дело что в конструкторе у меня явно объявляеться:
    fFolderID := -1;
    При этом если в дизайнере устонавливаю значение, для данного свойства, отличное от 0,
    то все сохраняется, если  0 то не сохраняется.
    Про Store и т.д. я прекрасно знаю, и знаю как обойти данную проблемму, в конкретном
    случае. Вопрос в том откуда у данного поведения "ноги растут", т.к. в друм случае такой эффект можно и не заметить
  • Наиль © (26.12.06 09:02) [4]
    Не совсем внимательно прочитал [1], поэтому рекомендовал этот способ.
    На самом деле я хотел сказать "не используй default" (явно объявил значение).
    -1 - число особенное, так что см. генофонд.
    TToolButton.ImageIndex
  • atruhin © (26.12.06 15:54) [5]
    Спасибо за ответы, но вариант > "не используй default"
    не слишком хорош, хранить абсолютно все умалчиваемые значения в ресурсе
    формы не очень хорошо.
  • Наиль © (26.12.06 16:30) [6]

    > хранить абсолютно все умалчиваемые значения в ресурсе
    > формы не очень хорошо.

    А все и не надо. Только те, что равны -1.
  • Slava80 (27.02.07 03:27) [7]
    Похожая проблема: не сохраняется свойство типа Double если в design-time задаю его равным нулю (0)

    Хелп говорит:
    The default and nodefault directives are supported only for ordinal types and for set types...
    ...For reals, pointers, and strings, there is an implicit default value of 0, nil, and '' (the empty string), respectively.


    Т.е. задать значение по умолчанию можно только целочисленным переменным (свойствам). А для reals (в моем случае Double) значение по умолчанию равно нулю.

    Кстати там же сказано:
    Note
    You can't use the ordinal value 2147483648 has a default value. This value is used internally to represent nodefault.


    Вообще число 2147483648 может легко превратиться в -1 если рассматривать его как знаковое 32 битное (signed 32-bit). Может быть поэтому default -1 воспринималось для Int64 как nodefault?

    Так вот, возвращаясь к Double, хотелось бы узнать как заставить сохранять свойство даже если оно равно неявному значению по умолчанию - нулю?
    ПОМОГИТЕ!
  • DimaBr (27.02.07 09:00) [8]
    property A: double read GetA write SetA stoted TRUE;

  • Slava80 © (28.02.07 02:46) [9]
    Позвольте возразить.
    Ради эксперимента создал простую компоненту.

    unit JustTest;

    interface

    uses
     SysUtils, Classes, Controls;

    type
     TJustTest = class(TGraphicControl)
     private
       FA: Double;
       function GetA: double;
       procedure SetA(const Value: double);
       { Private declarations }
     protected
       { Protected declarations }
     public
       constructor Create(AOwner: TComponent); override;
       { Public declarations }
     published
       property A: double read GetA write SetA stored TRUE;
       { Published declarations }
     end;

    procedure Register;

    implementation

    procedure Register;
    begin
     RegisterComponents('Samples', [TJustTest]);
    end;

    { TJustTest }

    constructor TJustTest.Create(AOwner: TComponent);
    begin
     inherited Create(AOwner);
    end;

    function TJustTest.GetA: double;
    begin
     Result:=FA;
    end;

    procedure TJustTest.SetA(const Value: double);
    begin
     FA:=Value;
    end;

    end.



    Установил и кинул на форму.
    В Инспекторе Объектов у свойства A установлено значение 0. Нажимаю Alt-F12:

    object Form1: TForm1
     Left = 213
     Top = 103
     Width = 696
     Height = 480
     Caption = 'Form1'
     Color = clBtnFace
     Font.Charset = DEFAULT_CHARSET
     Font.Color = clWindowText
     Font.Height = -11
     Font.Name = 'MS Sans Serif'
     Font.Style = []
     OldCreateOrder = False
     PixelsPerInch = 96
     TextHeight = 13
     object JustTest1: TJustTest
       Left = 272
       Top = 152
       Width = 100
       Height = 41
     end
    end



    Не сохранилось. Нажимаю Alt-F12. Задаю свойству A значение 1. Нажимаю Alt-F12:

    object Form1: TForm1
     Left = 213
     Top = 103
     Width = 696
     Height = 480
     Caption = 'Form1'
     Color = clBtnFace
     Font.Charset = DEFAULT_CHARSET
     Font.Color = clWindowText
     Font.Height = -11
     Font.Name = 'MS Sans Serif'
     Font.Style = []
     OldCreateOrder = False
     PixelsPerInch = 96
     TextHeight = 13
     object JustTest1: TJustTest
       Left = 272
       Top = 152
       Width = 100
       Height = 41
       A = 1.000000000000000000
     end
    end



    Сохранилось.

    Извините за обилие текста.
    И позвольте еще немного цитат из хелпа:

    If a property has no stored directive, it is treated as if stored True were specified.
    ...
    When saving a component's state, the storage specifiers of the component's published properties are checked. If a property's current value is different from its default value (or if there is no default value) and the stored specifier is True, then the property's value is saved. Otherwise, the property's value is not saved.


    Т.е. во-первых stored TRUE является умолчанием (соглашусь, что можно и прописать лишний раз для пущей уверенности). А во-вторых stored является лишь необходимым, но не достаточным условием для сохранения значения. Т.е. (если значение свойства равно умолчанию) И (stored = true) ТОГДА сохранять.
  • DimaBr (28.02.07 09:18) [10]
    А так ???
    TMyPanel = class(TCustomPanel)
     private
       fA: double;
     protected
       procedure DefineProperties(Filer: TFiler);override;
       procedure LoadCompProperty(Reader: TReader);
       procedure WriteCompProperty(Writer: TWriter);
     published
       property A: double read fA write fA stored false;
    end;

    implementation

    procedure TMyPanel.DefineProperties(Filer: TFiler);
    begin
     inherited;
     Filer.DefineProperty('A', LoadCompProperty, WriteCompProperty, true);
    end;

    procedure TMyPanel.LoadCompProperty(Reader: TReader);
    begin
     A := Reader.ReadFloat;
    end;

    procedure TMyPanel.WriteCompProperty(Writer: TWriter);
    begin
     Writer.WriteFloat(A);
    end;

  • Slava80 © (01.03.07 17:27) [11]
    Да! Так все работает. СПАСИБО!
    Значит все-таки есть возможность обойти эту проблему. А то я уже начал думать, что такое просто не возможно.
    Мне бы теперь разобраться что такое Reader и Writer. :)
  • DimaBr (02.03.07 10:08) [12]
    Это два метода, которые сохраняют и читают значения из ресурса (DFM). Записать можно любое свойство (даже private) и любым способом - главное чтобы можно было потом прочитать.
    А вот

    procedure DefineProperties(Filer: TFiler);override;


    как раз срабатывает при записи/чтении свойств из ресурса, переопределив который можно указать чтобы ещё мы хотели сохранить и какие методы будут этим заниматься.
  • Slava80 © (14.03.07 22:39) [13]
    Я прошу прощения, но в конце моего сообщения номер [9] закралась досадная опечатка. Я понимаю, что это не принципиально, но хочется, чтобы эта ветка помогла другим людям понять схему, по которой сохраняются свойства.

    И так, в конце [9] читать:
    "...ЕСЛИ (значение свойства НЕ равно умолчанию) И (Stored = TRUE) ТОГДА сохранять..."

    Чтобы оправдать этот пост, еще пробегусь по нескольким интересным местам в исходниках VCL (вы их, кажется, "генофондом" называете).

    unit Classes;
    ...
    procedure TWriter.WriteProperties(Instance: TPersistent);
    ...
    begin
    ...
           if IsStoredProp(Instance, PropInfo) then
             WriteProperty(Instance, PropInfo);
    ...
    end;



    В коде выше через вызов IsStoredProp (находящийся в TypInfo.pas) проверяется: равно ли Stored TRUE, и если да, то вызывается WriteProperty из того же Classes.pas.
    Посмотрим на WriteProperty:

    procedure TWriter.WriteProperty(Instance: TPersistent; PropInfo: PPropInfo);
    ...
    begin
     // Using IsDefaultPropertyValue will tell us if we should write out
     // a given property because it was different from the default or
     // different from the Ancestor (if applicable).
    ...
       if not IsDefaultPropertyValue(Instance, PropInfo, GetLookupInfo) then
       begin
    ...
         case PropType^.Kind of
           tkInteger, tkChar, tkEnumeration, tkSet:
             WriteOrdProp;
    ...
         end;
       end;
    ...
    end;



    В коде выше через вызов IsDefaultPropertyValue проверяется: равно ли свойство значению по умолчанию, и если НЕТ, то в зависимости от типа свойства вызывается соответствующая подпроцедура для его сохранения. Для сокращения кода оставил только WriteOrdProp.
    Посмотрим теперь на IsDefaultPropertyValue:

    function IsDefaultPropertyValue(Instance: TObject; PropInfo: PPropInfo;
    ...
     function IsDefaultOrdProp: Boolean;
     var
       Value: Longint;
       Default: LongInt;
     begin
       Value := GetOrdProp(Instance, PropInfo);
       if AncestorValid then
         Result := Value = GetOrdProp(Ancestor, PropInfo)
       else
       begin
         Default := PPropInfo(PropInfo)^.Default;
         Result :=  (Default <> LongInt($80000000)) and (Value = Default);
       end;
     end;



    Функция содержит подфункции отдельно для каждого типа свойства. Выше приведена IsDefaultOrdProp, которая срабатывает для порядковых. Int64 сюда не входит!!! В общем здесь все прозрачно: условие (Default <> LongInt($80000000)) проверяет не равно ли значение по умолчанию числу 2147483648, что равнозначно директиве nodefault. Т.е. ЕСЛИ (НЕТ директивы nodefault) И (Свойство равно значению по умолчанию), то IsDefaultOrdProp возвращает TRUE.
    Подфункции для типов Float и Int64 похожи:

     function IsDefaultFloatProp: Boolean;
     var
       Value: Extended;
     begin
       Value := GetFloatProp(Instance, PropInfo);
       if AncestorValid then
         Result := Value = GetFloatProp(Ancestor, PropInfo)
       else
         Result := Value = 0;;
     end;

     function IsDefaultInt64Prop: Boolean;
     var
       Value: Int64;
     begin
       Value := GetInt64Prop(Instance, PropInfo);
       if AncestorValid then
         Result := Value = GetInt64Prop(Ancestor, PropInfo)
         else
       Result := Value = 0;
     end;



    В них как и выше я не рассматриваю случай с предками (if AncestorValid then), потому что пока не до конца понимаю что это. Видимо это связано со свойствами взятыми у предков класса. Если кто разберется, поделитесь.
    Для данной же ветки форума важна одна строчка, одинаковая как для типа Float, так и Int64:
    Result := Value = 0;


    Т.е. в исходниках VCL для этих типов жестко прописано значение по умолчанию НОЛЬ. И никакие директивы default или nodefault при этом не учитываются!

    Это собственно и является ответом на самое первое сообщение темы. Также это опровергает мои домыслы в [7] насчет числа "-1".
  • GrayFace © (16.03.07 19:33) [14]
    Slava80   (27.02.07 3:27) [7]
    Вообще число 2147483648 может легко превратиться в -1 если рассматривать его как знаковое 32 битное (signed 32-bit). Может быть поэтому default -1 воспринималось для Int64 как nodefault?

    C 4.... путаешь. 2147483648 превратится в -2147483648.
 
Конференция "Компоненты" » Не сохраняется свойство
Есть новые Нет новых   [134427   +38][b:0][p:0.004]