2. Построение редактора свойства

Собственно построение пользовательского редактора свойств сводится к двум операциям.

Во-первых, это - описание нового класса редактора, порожденного от класса TPropertyEditor или одного из его потомков. Настройка редактора свойства выполняется перекрытием нескольких ключевых методов.

Во-вторых, регистрация редактора свойств для определенных типов свойств и классов компонентов с помощью процедуры RegisterPropertyEditor.

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

Например, свойство FormatAzimuth отвечает за форматирование значения угла. Было бы удобно предоставить возможность выбрать один из возможных вариантов, оставив возможность ввести значение вручную.

Примечание

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

Внимание

Редакторы свойств никак не влияют на работу компонента во время выполнения (Runtime).

2.1. Создание класса редактора свойств

2.1.1. Усовершенствование TStringProperty

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

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

Во-первых, необходимо перекрыть метод GetAttributes для того, чтобы оповестить инспектор объектов о том, каким образом допускается редактировать свойство.

Во-вторых, для формирования списка вариантов значений необходимо переопределить метод GetValues.

Таким образом, интерфейсная часть редактора свойства будет выглядеть следующим образом:

Пример 12.1.

  TFormatAngleProperty=class(TStringProperty)
    public
    function GetAttributes: TPropertyAttributes; override;
    procedure GetValues(Proc: TGetStrProc); override;
   end;

Реализация метода-функции GetAttributes заключается в возврате определенных элементов множества типа TPropertyAttributes.

Многим элементам этого множества соответствуют методы редактора свойств.

Примечание

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

Наиболее важные элементы множества и соответствующие им методы редактора свойств приведены в таблице.

Таблица 12.2.
Атрибуты свойствСоответствующий методОписание
paValueListGetValuesЭтот атрибут определяется для редакторов, которые требуют список элементов, подлежащих отображению в раскрывающемся списке. Если этот атрибут установлен, для заполнения списка вызывается метод GetValue.
paSortListЭтот атрибут инструктирует Инспектор объектов выполнить сортировку списка элементов, отображаемых в раскрывающемся списке. Разрешен только в том случае, если paValueList также установлен.
paSubPropertiesGetPropertiesЭтот атрибут показывает, что редактор свойства определяет подсвойство, которое должно быть отображено углубленным и ниже текущего свойства. Если этот атрибут установлен, для генерации списка свойств вызывается метод GetProperties.
paDialogEditЭтот атрибут устанавливается для редакторов свойств, которые отображают диалоговое окно в своем методе Edit. Этот атрибут должен быть установлен для того, чтобы в Инспекторе объектов справа от свойства появилась кнопка с многоточием.
paMultiSelectКогда этот атрибут установлен, это свойство отображается при выборе нескольких компонентов.
paAutoUpdateSetValueЭтот атрибут предписывает Инспектору объектов вызывать метод SetValue после каждого изменения, выполненного в значении свойства. Если этот аттрибут не определен, SetValue вызывается только в том случае, если пользователь нажимает клавишу <Enter> или перемещается из текущего свойства.
paReadOnlyЭтот атрибут устанавливается для предотвращения модификации пользователем значения свойства.
paVolatileSubPropertiesGetPropertiesИнспектор объектов "освежает" значения подсвойств, если значение свойства было изменено.
paReferenceGetComponentValueЗначение является ссылкой. Вместе с атрибутом paSubProperties означает, что объект-ссылка показывается как подствойство.
paFullWidthNameВместо значение свойства отображается его название.

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

Пример 12.2.

function TFormatAngleProperty.GetAttributes: TPropertyAttributes;
begin
  Result:=[paValueList, paAutoUpdate];
end;

Совет

Если нужно, чтобы значения были отсортированы, то нужно добавить атрибут paSortList.

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

В соответствии с таблицей 1, если включен атрибут paValueList, то для формирования самих значений должен быть реализован метод GetValues.

Метод GetValues имеет один параметр процедурного типа, который вызывается для каждого помещаемого в список значения.

Пример 12.3. Пример реализации метода GetValues

procedure TFormatAngleProperty.GetValues(Proc: TGetStrProc);
begin
  inherited;
  Proc('%d °');
  Proc('%d');
  Proc('a=%d');
  Proc('a=%d °');
end;

Результат работы редактора свойства приведен на рис.

Рис. 2. Редактор свойства в действии

Рис. 12.2. Рис. 2. Редактор свойства в действии


2.1.2. Редактор с формой

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

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

Вариант диалога приведен на рис. 3.

Рис. 3. Диалог редактирования свойства Azimuth

Рис. 12.3. Рис. 3. Диалог редактирования свойства Azimuth


Для того, чтобы обеспечить изменение свойства с использованием диалога нужно в методе GetAttributes включить атрибут paDialog:

Пример 12.4.

function TAzimuzhProperty.GetAttributes: TPropertyAttributes;
begin
 Result := [paDialog];
end;

Создание и вызов диалога редактирования производится в соответствующем атрибуту paDialog методе Edit:

Пример 12.5.

procedure TAzimuzhProperty.Edit;
begin
  inherited;
  dlgAzimuth:=TdlgAzimuth.Create(Application);
  try
  dlgAzimuth.Caption:= Format('%s.%s.%s',[TComponent(GetComponent(0)).Owner.Name, TComponent(GetComponent(0)).Name ,GetName ]);
  dlgAzimuth.Compass1.Azimuth:=TAzimuth(GetOrdValue);
  if dlgAzimuth.ShowModal=mrOk then SetOrdValue(dlgAzimuth.Compass1.Azimuth);
  finally
  dlgAzimuth.Free;
  end;
end;

После создания диалога его заголовок устанавливается равным имени "хозяина" компонента, имени компонента и имени свойства, разделяемыми точками. Затем свойство Azimuth компонента на диалоге устанавливается равным значению редактируемого свойства.

Если диалог закрылся подтверждением, то с помощью метода SetOrdValue устанавливается значение редактируемого свойства.

Рис. 4. Диалоговый редактор свойства в действии

Рис. 12.4. Рис. 4. Диалоговый редактор свойства в действии


Как это выглядит в действии можно увидеть здесь.

Совет

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

2.2. Регистрация редактора свойств

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

Процедура RegisterPropertyEditor принимает четыре параметра:

  1. Информация о типе редактируемого свойства, который получается с помощью функции TypeInfo;

  2. Тип компонента, для которого регистрируется редактор. Если это параметр равен nil, то редактор будет зарегистрирован для всех свойств того типа, информация о котором передано первым параметром;

  3. Название свойства, для которого регистрируется редактор. Если параметр равен пустой строке, то редактор будет зарегистрирован для всех свойств того типа, который передан вторым параметром.

  4. Класс редактора свойства.

Пример 12.6.

procedure Register;
begin
  RegisterPropertyEditor(TypeInfo(string),TCompass,
'FormatAzimuth',TFormatAngleProperty);
  RegisterPropertyEditor(TypeInfo(TAzimuth),TCompass,'Azimuth',TAzimuzhProperty);
end;

Примечание

Регистрация осуществляется внутри процедуры с предопределенным именем Register того модуля, в котором размещены классы редакторов свойств.