2. Свойства различных типов

2.1. Простые свойства

К простым относятся свойства числового, строкового и символьного типов. Их значения просто редактируются в Инспекторе объектов с помощью клавиатуры.

Редактор свойств простых типов

Рис. 2.1. Редактор свойств простых типов


Однако и здесь есть особенности, связанные с различной реализацией редакторов свойств одного и того же типа, в зависимости от того, какое имя имеет свойство. Например, при редактировании строкового свойства Name любого компонента оно не обновляется до тех пор, пока не будет нажата клавиша Enter или строка редактирования в Инспекторе объектов не потеряет фокус. В то же время при редактировании свойства Caption (тоже строкового) значение свойства изменяется с каждым нажатием клавиши.

2.2. Свойства перечислимых типов

Для создания свойства перечислимого типа нужно воспользоваться существующим или объявить свой перечислимый тип и объявить свойство этого типа.

Совет

Напомню, что перечислимыми (enumerated) называются типы данных, заданные исчерпывающим списком всех возможных значений для переменных этого типа.

Внимание

Не путать перечислимый (enumerated) тип с перечисляемым (ordinal) типом, у которых каждое значение, кроме первого, имеет уникального предшественника, а каждое значение, кроме последнего, имеет уникального последователя

Простой пример объявления перечислимого типа:

Пример 2.4.

           TAnswer = (ansYes, ansNo, ansMaybe);
         

Свойства перечислимых типов можно редактировать в Инспекторе объектов выбирая требуемое значение из выпадающего списка (рис. 2.2).

Редактор свойств перечислимого типа

Рис. 2.2. Редактор свойств перечислимого типа


При этом для некоторых типов, элементы которых имеют графическое представление, в списке дополнительно появляются маленькие картинки, иллюстрирующие значение элемента.

Для свойств перечислимых типов сохраняется возможность изменять их значения и с клавиатуры, но при этом нужно следить за тем, чтобы введенное значение было одним из элементов перечислимого типа.

2.3. Свойства типа множество

Тип множество является производным от перечислимого типа и фактически представляет собой набор из элементов перечислимого типа. Объявляется множество с использованием языковой конструкции set of.

Пример 2.5. Пример объявления типа множество

           TAnswer = (ansYes, ansNo, ansMaybe);
           TAnswerSet= set of TAnswer;
         

Инспектор объектов для редактирования и изменения множеств предоставляет следующий способ.

Редакторы свойств типа множество

Рис. 2.3. Редакторы свойств типа множество


Слева от имени свойства возникает квадрат с крестиком, нажатие на который приводит к распахиванию дерева элементов. Включение элемента в множество показывается с помощью логического значения: True, если элемент включен в множество и False – если не включен.

2.4. Свойства объектного типа

Свойства объекта могут в свою очередь сами являться объектами. Свойства-объекты разворачиваются в Инспекторе объектов таким образом, чтобы его свойства могли быть модифицированы.

При использовании свойств-объектов возможны два варианта: во-первых, свойство-объект может являться объектом, создаваемым внутри компонента, а во-вторых – свойство может являться ссылкой на другой компонент. Рассмотрим оба варианта.

2.4.1. Свойство-объект

Для того чтобы опубликованные свойства-объекта могли быть сохранены в файле формы, объект должен являться наследником TPersistent. Выполнить это требование очень просто, поскольку TPersistent является прямым наследником TObject.

Редактор свойства объектного типа

Рис. 2.4. Редактор свойства объектного типа


Так как свойство представляет собой объект, а все объекты в Delphi являются динамически размещаемыми в памяти, то использование свойств-объектов влечет за собой необходимость создания экземпляра в конструкторе класса и уничтожения его в деструкторе.

Например, в разрабатываемом классе необходимо использовать некоторую картинку. Для этого можно использовать класс TBitmap, объявить свойство соответствующего типа и создать в конструкторе экземпляр класса. После использования объекта в деструкторе необходимо уничтожить объект-свойство, высвободив занимаемую им память.

Пример 2.6. Пример использования свойства-объекта

             type
             TControl2 = class(TGraphicControl)
             private
             FBitmap: TBitmap;
             procedure SetBitmap(const Value: TBitmap);
             protected
             procedure Paint; override;
             public
             constructor Create(AOwner: TComponent); override;
             destructor Destroy; override;
             published
             property Bitmap: TBitmap read FBitmap write SetBitmap;
             end;
             implementation
             ...
             constructor TControl2.Create(AOwner: TComponent);
             begin
             inherited;
             FBitmap:=TBitmap.Create;
             end;
             
             destructor TControl2.Destroy;
             begin
             FBitmap.Free;
             inherited;
             end;
             
             procedure TControl2.Paint;
             begin
             inherited;
             Canvas.Draw(0,0,FBitmap);
             end;
             
             procedure TControl2.SetBitmap(const Value: TBitmap);
             begin
             FBitmap.Assign(Value);
             Invalidate;
             end;
           

Совет

Обратите внимание, что имеет определенные особенности и метод записи свойства объектного типа. Вместо прямого присвоения используется метод Assign, копирующий все атрибуты объекта.

2.4.2. Свойство как ссылка на компонент

При создании свойства, являющейся фактически ссылкой на другой компонент не нужно создавать экземпляр в конструкторе. Достаточно объявить свойство нужного типа, задать методы чтения и записи.

Но в этом случае существует другая сложность. Если компонент, на который мы создали ссылку будет удален, то ссылка на него окажется некорректной и возникнет ошибка доступа к несуществующему объекту. Для устранения такого нежелательного эффекта следует переопределять метод Notification, который вызывается когда объект-ссылка создается или уничтожается.

Пример 2.7. Пример использования метода Notification

             type
             TControl2 = class(TGraphicControl)
             private
             FFileLabel: TLabel;
             protected
             procedure Notification(AComponent: TComponent; 
             Operation: TOperation); override;
             published
             property FileLabel: TLabel read FFileLabel write FFileLabel;
             end;
             
             implementation
             ...
             procedure TControl2.Notification(AComponent: TComponent;
             Operation: TOperation);
             begin
             inherited;
             if (Operation=opRemove) and  (AComponent=FFileLabel) then FFileLabel:=nil;
             end;
           

Достаточно проконтролировать момент уничтожения объекта-ссылки и установить внутренне поле в nil.