Инспектор объектов и метаданные

Как уже было сказано, класс TGsvObjectInspectorTypeListInfo предоставляет дополнительную функциональность при работе со свойствами - перечислимыми типами. Класс переопределяет методы IntegerToString, StringToInteger и FillList, а для задания списка перечислений вводит новый виртуальный метод ListEnumItems - этот метод напоминает ChildrenInfo базового класса, но возвращает не типовые метаданные, а свойства каждого элемента перечисления - его имя и ассоциированное с ним значение - эти параметры определены записью TGsvObjectInspectorListItem. Конкретный метакласс, описывающий свойства-перечисления может быть порожден от класса TGsvObjectInspectorTypeListInfo, причем достаточно будет переопределить только метод ListEnumItems. Метод FillList выполняет итерацию по всем перечислимым значениям, вызывая ListEnumItems с монотонно возрастающим индексом до тех пор, пока ListEnumItems не вернет значение nil. Результаты итерации передаются визуальному компоненту инспектора через параметр List. Для преобразования строкового вида значения перечисления к целочисленному виду и для обратного преобразования служат методы StringToInteger и IntegerToString, алгоритм которых очень похож - оба они итерируют список перечислений, но в первом случае критерием для поиска является строковое имя, а во втором случае - ассоциированное с ним значение. Очевидно, что такой базовый класс может быть использован для любых перечислимых типов, причем даже таких, в которых значения перечисления не образуют упорядоченную монотонную последовательность.

type
 TGsvObjectInspectorTypeFontInfo = class(TGsvObjectInspectorTypeInfo)
 public
  class procedure ShowDialog(Inspector: TComponent;
  Info: PGsvObjectInspectorPropertyInfo;
  const EditRect: TRect); override;
  class function ObjectToString(const Value: TObject):
  String; override;
 end;
 class procedure TGsvObjectInspectorTypeFontInfo.ShowDialog(
  Inspector: TComponent;
  Info: PGsvObjectInspectorPropertyInfo; const EditRect: TRect);
 var
  dlg: TFontDialog;
  fnt: TFont;
 begin
  if not Assigned(Info) then
  Exit;
  if not Assigned(Info^.NestedObject) then
  Exit;
  if not (Info^.NestedObject is TFont) then
  Exit;
  fnt := TFont(Info^.NestedObject);
  dlg := TFontDialog.Create(Inspector);
  try
  dlg.Font.Assign(fnt);
  if dlg.Execute then
  fnt.Assign(dlg.Font);
  finally
  dlg.Free;
  end;
 end;
 class function TGsvObjectInspectorTypeFontInfo.ObjectToString(
  const Value: TObject): String;
 begin
  if Assigned(Value) then
  if Value is TFont then
  with TFont(Value) do
  Result := Format('%s, %d', [Name, Size]);
 end;

Класс TGsvObjectInspectorTypeFontInfo демонстрирует способ создания метакласса для специфического редактора свойства, в данном случае, для свойства-шрифта, имеющего тип TFont. Здесь переопределяются два метода - ShowDialog и ObjectToString. Методу ShowDialog передаются три аргумента: ·Inspector - родительский компонент для формы-диалога, ·Info - метаданные свойства, ·EditRect - прямоугольник, представляющий собой экранные координаты поля редактирования визуального компонента инспектора. Эти координаты можно использовать для того, чтобы расположить диалог, скажем, прямо под значением редактируемого свойства (подобно списку). Конечно, это имеет смысл только для небольших по размеру диалогов.
Для свойств, отображающих диалог, менеджер заполняет поле метаданных NestedObject - оно указывает на инспектируемый объект или его заместитель. В данном случае менежер увидит, что свойство-шрифт является объектом-классом и определит его адрес, используя адрес объекта верхнего уровня в дереве объектов-свойств и имя свойства. Если бы это было простое свойство, например, TColor, то менеджер заполнил бы поле NestedObject указателем на объект текущего уровня.
После того, как мы определили, что инспектируемое свойство действительно является объектом нужного нам типа (в данном случае TFont), мы создаем диалог, инициализируем его данные текущим значением свойства, отображаем диалог и при успешном завершении переносим новое значение свойства в инспектируемый объект.
Другой метод класса - ObjectToString определяет то, как будет выглядеть значение свойства в инспекторе. В данном случае мы считаем, что основные свойства шрифта - это его имя и размер. Такой способ отображения отличается от того, что мы видим в инспекторе Delphi - в качестве значения объекта Delphi отображает имя его типа.
Визуальный компонент инспектора
В этом разделе мы рассмотрим визуальный компонент инспектора, его основные методы и события, а также некоторые пользовательские аспекты, какие, как хинты. Причем, для простоты опустим аспекты реализации и, кроме того, будем использовать понятия "инспектор" и "визуальный компонент инспектора" как синонимы.
Как это принято в Delphi, визуальный компонент представлен в двух формах - как TGsvCustomObjectInspectorGrid и, соответственно, TGsvObjectInspectorGrid. Опуская детали реализации и не очень важные свойства, класс инспектора определяется так:

type

 TGsvCustomObjectInspectorGrid = class(TCustomControl)

 protected

  property LongTextHintTime: Cardinal;

  property LongEditHintTime: Cardinal;

  property AutoSelect: Boolean;

  property HideReadOnly: Boolean;

  property OnEnumProperties:

  TGsvObjectInspectorEnumPropertiesEvent;

  property OnGetStringValue:

  TGsvObjectInspectorGetStringValueEvent;

  property OnSetStringValue:

  TGsvObjectInspectorSetStringValueEvent;

  property OnGetIntegerValue:

  TGsvObjectInspectorGetIntegerValueEvent;

  property OnSetIntegerValue:

  TGsvObjectInspectorSetIntegerValueEvent;

  property OnFillList:

  TGsvObjectInspectorFillListEvent;

  property OnShowDialog:

  TGsvObjectInspectorShowDialogEvent;

  property OnHelp: TGsvObjectInspectorInfoEvent;

  property OnHint: TGsvObjectInspectorInfoEvent;

 public

  procedure NewObject;

  procedure Clear;

  procedure ExpandAll;

  procedure CollapseAll;

 end;

Вначале отметим самые простые свойства и методы: ·AutoSelect - если AutoSelect установить в True, то при выборе свойства, доступного для редактирования весь его текст будет выделяться, ·HideReadOnly - если установить в True, то инспектор будет скрывать все свойства, доступные только по чтению, ·Clear - вызов этого метода очистит инспектор, что означает отсутствие инспектируемого объекта, ·ExpandAll - раскрыть все вложенные веточки дерева свойств, ·CollapseAll - свернуть все вложенные веточки.
Цикл событий инспектора при инспектировании начинается с вызова метода NewObject. Это приведет к тому, что инспектор начнет циклически вызывать событие OnEnumProperties. Сигнатура обработчика этого события следующая:

TGsvObjectInspectorEnumPropertiesEvent = procedure(Sender: TObject;

 Index: Integer; out Info: PGsvObjectInspectorPropertyInfo) of object;

Обработчику передается монотонно увеличивающееся значение Index и, при каждом обращении, обработчик должен вернуть в out-аргументе указатель на метаданные очередного свойства или nil, если все свойства перечислены. Обработчик может выглядеть так:

procedure TForm1.OnEnumProperties(Sender: TObject; Index: Integer;

  out Info: PGsvObjectInspectorPropertyInfo);

 begin

  Info := ObjectManager.PropertyInfo(Index);

 end;

Отправить комментарий

Проверка
Антиспам проверка
Image CAPTCHA
...