PERSIST SRC
{interface} type DemoComponent = class(TComponent) private fGlyph: TBitmap; fGlyphWritten: boolean; procedure SetGlyph(Glyph: TBitmap);
{ снаружи не видно } protected constructor Create(Owner: TComponent);
override; procedure Loaded; override; public published property Glyph: TBitmap read fGlyph write SetGlyph; end; {implementation} constructor DemoComponent.Create(Owner: TComponent);
begin inherited Create(Owner);
fGlyph := TBitmap.Create; { Обязательно создайте для данного поля пустой объект } end; procedure DemoComponent.SetGlyph(Glyph: TBitmap);
begin if fGlyph <>
Glyph then { fGlyph = Glyph, когда SetGlyph } begin { вызывается процедурой Loaded } fGlyph.Free; { Assign может закончиться неудачно, } { если целевое поле не пусто: } fGlyph := TBitmap.Create; { Free/Create/Assign намного надежнее } fGlyph.Assign(Glyph);
end; { Извлекаем все необходимые данные и устанавливаем флаг PropertyWritten} fGlyphWritten := True; end; procedure DemoComponent.Loaded; begin inherited Loaded; { Не забывайте сделать это! } if (not fGlyphWritten) and (not fGlyph.Empty) then SetGlyph(fGlyph);
{ Извлекаем все необходимые данные } end;
С частичной загрузкой дело обстоит несколько сложнее. К счастью, компоненты Delphi содержат метод Loaded, который можно переопределить для выполнения любых завершающих действий. С помощью метода Loaded и незначительных изменений в программе проблему частичной загрузки удается решить.
Первое, что необходимо сделать, — добавить флаг fPropertyWritten для каждого свойства TPersistent, которое может сохраняться (см. листинг 9.1). При создании объекта флагу присваивается значение False, и лишь в методе write оно может измениться на True.
Затем следует переопределить (с помощью ключевого слова override) метод Loaded вашего компонента и добавить в него строку примерно такого вида:
if not fPropertyWritten then
SetProperty(fProperty)
чтобы метод write вызывался из Loaded в том (и только в том!) случае, если он не был вызван при загрузке компонента.
Наконец, представьте себе, что произойдет при попытке присвоить свойству типа TPersistent тот же самый объект, который в нем уже содержится. Вы уничтожаете имеющееся значение (Free), создаете новый «пустой» экземпляр (Create) и затем присваиваете (Assign) ему новое значение, которое указывает на первоначальный (уже уничтоженный вами) экземпляр. Вряд ли это то, что вы хотели получить! Избежать такой ситуации можно, воспользовавшись фрагментом кода, приведенным в листинге 9.2. При этом private-объект уничтожается лишь в том случае, если новое значение не совпадает с существую щим. Дополнительная проверка гарантирует, что SetProperty(fProperty) больше не приведет к возникновению GPF и не станет причиной особых накладных расходов, если «чтение вместо записи» все же исчезнет из Delphi.