2015-12-11 3 views
2

Как установить значение свойства объекта компонента по умолчанию?Delphi 2009: Значение по умолчанию объекта Component Object

компоненты Код класс:

unit CustomClass; 

interface 

uses 
    Classes; 

type 
    TCustomClass = class; 

    TConfiguration = class; 

    TCustomClass = class (TComponent) 
    private 
    FConfiguration: TConfiguration; 
    procedure SetConfiguration(const Value: TConfiguration); 
    published 
    property Configuration: TConfiguration read FConfiguration write SetConfiguration; 
    public 
    constructor Create(AOwner: TComponent); override; 
    destructor Destroy; override; 
    end; 

    TConfiguration = class (TPersistent) 
    private 
    FDelay: Integer; 
    FSize: Integer; 
    procedure SetDelay(const Value: Integer); 
    procedure SetSize(const Value: Integer); 
    published 
    property Delay: Integer read FDelay write SetDelay; 
    property Size: Integer read FSize write SetSize; 
    public 
    procedure Assign(Source: TPersistent); override; 
    end; 

implementation 

{ TCustomClass } 

constructor TCustomClass.Create(AOwner: TComponent); 
begin 
    inherited; 
    Configuration.FileName:= 'FileName'; 
    Configuration.Size := 10; 
end; 

destructor TCustomClass.Destroy; 
begin 
    Configuration.Free; 
    inherited; 
end; 

procedure TCustomClass.SetConfiguration(const Value: TConfiguration); 
begin 
    FConfiguration.Assign(Value); 
end; 

{ TConfiguration } 

procedure TConfiguration.Assign(Source: TPersistent); 
begin 
    inherited; 
    Delay := (Source as TConfiguration).Delay; 
    Size := (Source as TConfiguration).Size; 
end; 

procedure TConfiguration.SetDelay(const Value: Integer); 
begin 
    FDelay := Value; 
end; 

procedure TConfiguration.SetSize(const Value: Integer); 
begin 
    FSize := Value; 
end; 

end. 

В моем IDE будет отображаться как свойство объекта было изменено (жирным синим).

Я думал, что в создании по умолчанию и хранимые функции по свойствам класса TConfiguration, например, так:

TConfiguration

interface 

private 
    function FileNameStored: Boolean; 
published 
    property FileName: string read FFileName write SetFileName stored FileNameStored; 
    property Size: Integer read FSize write SetSize default 10; 

implementation 

function TConfiguration.FileNameStored: Boolean; 
begin 
    Result := FileName <> 'FileName'; 
end; 

окрашивает свойства TConfiguration в нормальных синий, но не свойство конфигурации TCustomClass, и я не хочу устанавливать его значения по умолчанию, находится на TCustomClass, так как TConfiguration может быть использован в других компонентах.

Тогда я подумал:

TCustomClass

interface 

private 
    function ConfigurationStored: Boolean; 
published 
    property Configuration: TConfiguration read FConfiguration write SetConfiguration stored ConfigurationStored; 

implementation 

function TCustomClass.ConfigurationStored: Boolean; 
begin 
    Result := Configuration.FileName <> 'FileName' and 
    Configuration.Size <> 10; 
end; 

Но это только устанавливает цвет конфигурации TCustomClass свойства в обычных синих, а не его свойства.

ОТВЕТ

Как @RemyLebeau указал (в первом и последнем ответе), были ошибки в коде. В этом компоненте и в этом случае я решил не устанавливать значения по умолчанию для свойств.

+0

Вы намеревались отбросить объект конфигурации на форму, а также удалить пользовательский класс в форму и затем подключить их? Или вы хотите, чтобы объект конфигурации был свойством, принадлежащим настраиваемому классу, и его не нужно вручную создавать и назначать? –

+1

Тогда вы действительно упустили некоторые очевидные вещи, как указывает Реми. Он показывает, что вам нужно явно создавать (в вашем конструкторе классов) и бесплатно (в деструкторе класса) все типы объектов TO, которые принадлежат (являются неотъемлемой частью) вашего объекта. У вас был базовый класс правильно, так что это хорошо. Вы можете добавить OnChange: TNotificationEvent в свой объект конфигурации. Таким образом, он может вызвать основной класс и заставить его что-то делать, когда кто-то пишет свойство конфигурации. –

+0

@WarrenP Да. Я исправил его, но, как заметил @NGLN, не имеет смысла исправлять его по этому вопросу, так как он делает ответ ненужным.«OnChange: TNotificationEvent» действительно хороший совет, мне понравилось, так как я могу изменить значение «хранимых» свойств, если они являются частной переменной класса. Благодарю. –

ответ

5

В коде есть несколько ошибок.

  1. TCustomClass ваш конструктор не создает TConfiguration объект. Вам нужно добавить, что:

    constructor TCustomClass.Create(AOwner: TComponent); 
    begin 
        inherited; 
        FConfiguration := TConfiguration.Create; // <-- add this 
        FConfiguration.FileName := 'FileName'; 
        FConfiguration.Size := 10; 
    end; 
    

    Это, как говорится, отнесение FileName и Size свойств, вероятно, должны быть перемещены в TConfiguration конструктор, а не TCustomClass конструктора.

  2. Свойство String не может быть определено с заданным пользователем значением по умолчанию, значение по умолчанию всегда является пустой строкой. Таким образом, ваше свойство FileName всегда будет изменяться, когда ваш компонент будет создан, потому что ваш конструктор присваивает ему значение по умолчанию. Ваш подход stored является правильным решением для его устранения. Или просто не присваивайте значение по умолчанию FileName at all, оставьте его пустым. Если пользователь не назначает явный FileName, ваш код может принять значение по умолчанию, если это необходимо.

    С другой стороны, свойство Integer может быть определено с использованием заданного пользователем значения по умолчанию. Ваше имущество Size этого не делает.Оно должно быть (особенно, если вы двигаетесь присвоение значения по умолчанию в TConfiguration конструктор):

    property Size: Integer read FSize write SetSize default 10; 
    
  3. ваш метод TConfiguration.Assign() осуществляется неправильно. Вызывая унаследованный метод Assign() перед копированием значений, ваш код всегда будет генерировать исключение EConvertError во время выполнения, если вызывающий абонент назначает один объект TConfiguration другому. Причина в том, что реализация базового класса TPersistent.Assign() просто вызывает Source.AssignTo(Self), а TConfiguration не переопределяет метод AssignTo(), поэтому вызывается TPersistent.AssignTo(), который просто вызывает Dest.AssignError(Self), что вызывает исключение. Так, НЕ вызывать унаследованный Assign() метод, если Source фактически TConfiguration объект:

    procedure TConfiguration.Assign(Source: TPersistent); 
    begin 
        if Source is TConfiguration then 
        begin 
        FDelay := TConfiguration(Source).Delay; 
        FSize := TConfiguration(Source).Size; 
        end else 
        inherited; 
    end; 
    
+0

Зачем мне переводить назначение TConfiguration из конструктора TCustomClass в конструктор TConfiguration? Это обычный способ написания классов компонентов? Потому что что делать, если в будущем я создам другой компонент и использую тот же класс TConfiguration? –

+2

Свойство класса является характеристикой этого класса. Значение по умолчанию этого свойства тоже. Это уже достаточно. Но особенно, когда вам нужно использовать этот класс в нескольких сценариях, вы должны создать его, чтобы он мог вести себя автономно. Таким образом, вы создаете «TConfiguration» в том классе, в котором он вам нужен, и там вы можете назначить пользовательские настройки, но настройки по умолчанию выполняются в самой 'TConfiguration'. – NGLN

+1

Это полностью зависит от вас. Если зеленое яблоко должно быть красным в корзине с фруктами, сделайте его красным при заполнении корзины. Но если зеленое яблоко должно иметь красные пятна, тогда вы должны создать пятнистое яблоко, способное иметь пятна перед созданием корзины. Или: если неважно, какой тип банана находится в корзине, зарегистрируйте тип банана после заполнения корзины. Но когда в корзине могут быть только бананы Chiquita, тогда применяйте это ограничение, создавая TChiquitaBanana из TBanana специально для этого типа корзины. – NGLN

0

Но это только устанавливает цвет TCustomClassConfiguration свойство к нормальным синим, а не его свойства.

Это по дизайну. A storage specifier работает только для свойства, для которого он указан.

Сравните ваш класс с TFont недвижимости на бланке. Когда ParentFont - True, имущество Font не будет сохранено. Но его члены Color и Name по-прежнему не имеют значения по умолчанию, поэтому они выглядят так, как будто они будут сохранены. Это связано с тем, что объект TFont не знает о его владельце, как он мог? Один раз он является частью холста, в другой раз он является частью контроля или вообще не имеет владельца. Во всех этих условиях объект TFont должен быть полностью функциональным, поэтому он не запрашивает у своего родителя, как он должен себя вести. С другой стороны: родитель не должен допрашивать своего ребенка о том, как себя вести.

Теперь вернитесь к своему сценарию: необходимо ли хранить FileName и Size свойства, которые должны храниться в TConfiguration. Должно ли быть сохранено свойство ConfigurationTCustomClass может быть не зависит от этих FileName и Size. Если свойство Configuration хранится (выделено полужирным шрифтом), но все его элементы не сохраняются (не выделены жирным шрифтом), а затем ничего не сохраняется в конце. Если у вас есть имущество ParentConfiguration, равно как ParentFont, то вы можете не хранить Configuration. В противном случае оставьте это, и пусть смелость не отвлекает вас дальше.

+0

Ваши слова верны. Но в этой цитате я попытался объяснить, что подход «сохраненный» «Конфигурация» не достаточен для удовлетворения моих потребностей, потому что он только делает «Конфигурация» нормальным синим, а не его свойствами, который останется синим. –