Содержание материала

 

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

Code:

TGsvObjectInspectorObjectInfo = class

public

   constructor Create;

   destructor Destroy; override;

   function ObjectName: String; virtual;

   function ObjectTypeName: String; virtual;

   function ObjectHelp: Integer; virtual;

   function ObjectHint: String; virtual;

   function PropertyInfo(Index: Integer): PGsvObjectInspectorPropertyInfo;

   procedure FillList(Info: PGsvObjectInspectorPropertyInfo;

             List: TStrings); virtual;

   procedure ShowDialog(Inspector: TComponent;

             Info: PGsvObjectInspectorPropertyInfo;

             const EditRect: TRect); virtual;

   function GetStringValue(Info: PGsvObjectInspectorPropertyInfo):

             String; virtual;

   procedure SetStringValue(Info: PGsvObjectInspectorPropertyInfo;

             const Value: String); virtual;

   function GetIntegerValue(Info: PGsvObjectInspectorPropertyInfo):

             LongInt; virtual;

   procedure SetIntegerValue(Info: PGsvObjectInspectorPropertyInfo;

             const Value: LongInt); virtual;

 

   property TheObject: TObject read GetObject write SetObject;

end;

 

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

Метод PropertyInfo напоминает метод ChildrenInfo метакласса - для каждого значения индекса функция возвращает указатель на метаданные свойства, а при завершении итерации по всем свойствам она возвращает nil. Наиболее существенное отличие от ChildrenInfo состоит в том, что PropertyInfo рекурсивно обходит все вложенные свойства и дополняет структуру TGsvObjectInspectorPropertyInfo несколькими динамически формируемыми полями. Здесь уместно упомянуть, что при описании записи TGsvObjectInspectorPropertyInfo мы опустили несколько полей, которые были неважны с точки зрения метаданных. Вот эти поля:

HasChildren: Boolean;

Level: Integer;

Expanded: Boolean;

TheObject: TObject;

NestedObject: TObject;

 

HasChildren - указывает на наличие у данного свойства вложенных подсвойств,

 

Level - уровень свойства в полном дереве свойств,

 

 

Expanded - признак того, что вложенные свойства раскрыты и отображаются,

 

TheObject - объект или заместитель, которому принадлежит свойство,

 

 

NestedObject - объект или заместитель вложенного свойства.

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

 

FillList - перенаправляет запрос на заполнение списка перечислимых значений свойства конкретному метаклассу вложенного свойства,

 

ShowDialog - перенаправляет запрос на отображение диалога-мастера конкретному метаклассу вложенного свойства,

 

 

GetStringValue - получает значение свойства инспектируемого объекта в строковом виде на основе RTTI. Если свойство имеет вложенный метакласс, то используется его специализация (запрос перенаправляется метаклассу), а иначе выполняется стандартное преобразование, например, из типа Double в тип String,

 

SetStringValue - устанавливает значение свойства на основе заданного строкового значения,

 

 

GetIntegerValue и SetIntegerValue - подобны двум предыдущим методам, но специализированы не на строковом, а на целочисленном значении свойства.

Говоря о перенаправлении запросов от менеджера, нельзя не упомянуть о тех методах метаклассов, которых мы только коснулись в первом разделе статьи. В текущей версии инспектора определено несколько вспомогательных специализированных классов, порожденных от базового класса TGsvObjectInspectorTypeInfo. Это:

 

TGsvObjectInspectorTypeListInfo - предоставляет дополнительную функциональность при работе со свойствами, реализующими перечислимые типы. Такие свойства отображаются в инспекторе как выпадающие списки,

 

TGsvObjectInspectorTypeSetInfo - помогает описывать свойства-множества,

 

 

TGsvObjectInspectorTypeFontInfo - специализируется на описании свойства типа TFont и инкапсулирует стандартный Windows-диалог выбора шрифта,

 

TGsvObjectInspectorTypeColorRGBInfo - специализируется на описании простого свойства типа TColor и инкапсулирует стандартный Windows-диалог выбора цвета.

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

Code:

type

TGsvObjectInspectorListItem = record

   Name: String// имя элемента списка

   Data: LongInt; // значение элемента списка

end;

PGsvObjectInspectorListItem = ^TGsvObjectInspectorListItem;

 

TGsvObjectInspectorTypeListInfo = class(TGsvObjectInspectorTypeInfo)

protected

   classfunction ListEnumItems(Index: Integer):

                   PGsvObjectInspectorListItem; virtual;

public

   classprocedure FillList(AObject: TObject; List: TStrings); override;

   classfunction IntegerToString(const Value: LongInt):

                   String; override;

   classfunction StringToInteger(const Value: String):

                   LongInt; override;

end;

 

classfunction TGsvObjectInspectorTypeListInfo.ListEnumItems(

   Index: Integer): PGsvObjectInspectorListItem;

begin

   Result := nil;

end;

 

classprocedure TGsvObjectInspectorTypeListInfo.FillList(AObject: TObject;

   List: TStrings);

var

   i: Integer;

   p: PGsvObjectInspectorListItem;

begin

   i := 0;

   p := ListEnumItems(0);

   while Assigned(p) dobegin

     List.AddObject(p^.Name, TObject(p^.Data));

     Inc(i);

     p := ListEnumItems(i);

   end;

end;

 

classfunction TGsvObjectInspectorTypeListInfo.IntegerToString(

   const Value: Integer): String;

var

   i: Integer;

   p: PGsvObjectInspectorListItem;

begin

   Result := '';

   i      := 0;

   p      := ListEnumItems(0);

   while Assigned(p) dobegin

     if p^.Data = Value thenbegin

       Result := p^.Name;

       Break;

     end;

     Inc(i);

     p := ListEnumItems(i);

   end;

end;

 

classfunction TGsvObjectInspectorTypeListInfo.StringToInteger(

   const Value: String): LongInt;

var

   i: Integer;

   p: PGsvObjectInspectorListItem;

begin

   Result := 0;

   i      := 0;

   p      := ListEnumItems(0);

   while Assigned(p) dobegin

     if p^.Name = Value thenbegin

       Result := p^.Data;

       Break;

     end;

     Inc(i);

     p := ListEnumItems(i);

   end;

end;

 

Добавить комментарий

Не использовать не нормативную лексику.

Просьба писать ваши замечания, наблюдения и все остальное,
что поможет улучшить предоставляемую информацию на этом сайте.

ВСЕ КОММЕНТАРИИ МОДЕРИРУЮТСЯ ВРУЧНУЮ, ТАК ЧТО СПАМИТЬ БЕСПОЛЕЗНО!


Защитный код
Обновить