Далее по тексту "особенностью" (Particularity) я буду называть свойство, событие или метод, заменяя тем самым словосочетание одним словом. Особенность - краеугольный камень реализации Инспектора. Физически особенность представляет собой запись TParticul: TParticulKind = (pkProperty, pkMethod, pkEvent); TParticul = record Name: string; Kind: TParticulKind; Data: Word; Enabled: Boolean; Visible: Boolean; Code: string; Info: string; ReadMode: Boolean; end; где
Name - имя особенности, отображаемое в Инспекторе, можно (и желательно!) на русском, каждая особенность обладает уникальным именем;
Kind - тип особенности, т. е. свойство это, метод или событие;
Data - шифр типа данных, служит для назначения данному событию определённого редактора (см. далее);
Enabled - показывает, разрешена особенность или запрещена;
Visible - показывает, видима особенность или нет (в основном для внутреннего использования, но можно использовать и в явном виде);
Code - кодированные данные в виде строки;
Info - дополнительные кодированные данные (например, для целых чисел - диапазон), не редактируются Инспектором;
ReadMode - особенность только для чтения (не работает в случае, когда особенность является методом).
В дальнейшем понадобится понятие массива данных TParticulList = class(TList). Этот класс - простой контейнер особенностей; при добавлении в него особенности он сразу же сортирует весь массив по именам особенностей. Также при добавлении особенности метод TParticulList.Add проверяет имя особенности (TParticul.Name) на уникальность; если особенность с таким именем уже содержится в массиве, создаётся исключительная ситуация EParticul.
Инспектор обрабатывает элементы управления специального вида, которые умеют генерировать массивы особенностей и принимать особенности:
Caption - имя элемента управления, отображаемое в Инспекторе (аналог свойства Name: TComponentName в Инспекторе Delphi);
GetTypeName - функция, выдающая название типа элемента управления (можно на русском!), также отображаемое в Инспекторе;
GetParticuls - функция, формирующая список особенностей данного элемента управления для передачи его в Инспектор;
MouseDown - обработчик щелчка мышью на элементе (далее будет рассмотрен подробнее);
FullText - формирует строку для отображения списка редактируемых объектов в Инспекторе (Result := FCaption + ': ' + GetTypeName);
SetParticul - осуществляет приём изменённой особенности из Инспектора.
Элементы TParticulControl можно использовать двумя способами. Первый - прямое использование; создаётся наследник, перекрывается, например, его метод Paint и элемент можно использовать. Этот способ подходит, например, в САПРах, где вся работа заключается только в редактировании элементов. Второй - косвенное использование; при этом способе TParticulControl служит как бы оболочкой для какого-либо другого элемента (не являющегося наследником TParticulControl и, вообще говоря, даже не являющегося наследником TControl). Для второго способа существует более удобный класс: TExternalControl = class(TParticulControl) private FExternalObject: TObject; procedure SetExternalObject(Value: TObject); procedure WMEraseBkgnd(var Message: TWmEraseBkgnd); message WM_ERASEBKGND; protected procedure CreateParams(var Params: TCreateParams); override; procedure Paint; override; public property ExternalObject: TObject read FExternalObject write SetExternalObject; procedure Refresh; end; где
ExternalObject - указатель на внешний объект, оболочкой которому служит данный элемент управления;
WMEraseBkgnd и CreateParams - перекрыты для обеспечения прозрачности;
Refresh - обеспечивает перерисовку при изменении размеров оболочки.
Элемент TExternalControl построен таким образом, что если редактируемый объект является наследником TControl, то при редактировании отображается именно он (в силу прозрачности TExternalControl), а если не является - отображается симпатичный квадратик (подобно как в Delphi отображаются невизуальные компоненты).