Создание и наследование элементов управления, редактирование особенностей
Редакторы-наследники TParticulEditor предполагают, что элемент управления TParticulEditor.Control будет "умещён в одну строку", т. е. данные, которые будут отображены в нём, можно отобразить в сравнительно "узком" элементе управления (20 пикселов). TParticulEditor имеет 4 стандартных наследника TEditEditor (редактор в виде TEdit), TButtonEditor (в виде TButton), TComboBoxEditor (в виде TComboBox), TCheckBoxEditor (в виде TCheckBox). В модуле автоматически регистрируются 11 основных типов данных, которые привязываются к редакторам следующим образом: к TEditEditor - строки, целые числа, действительные числа, к TButtonEditor - текст, выбор цвета и методы: без параметров, вычисление периметра элемента управления и масштабирование, к TComboBoxEditor - перечисление (в том числе и события), к TCheckBoxEditor - булевы величины.
Рассмотрим TEditEditor. Он редактирует данные трёх типов (в модуле PrtEdits). Всю "соль" обработки осуществляют процедуры TExecutor: StringExecutor, IntegerExecutor и RealExecutor. Так, StringExecutor просто переприсваивает данные из строки ввода TEdit редактируемой особенности, IntegerEdit и RealEdit перед присваиванием делают проверку формата вводимого числа из TEdit. Таким же образом, благодаря TExecutor можно обрабатывать любые данные, вводимые в строку.
Немного остановлюсь на TButtonEditor. Он служит, как правило, для обработки сложных данных, редактирование которых производится в диалоговом окне. Таким образом, кнопка редактора TButton служит для вызова некоторого диалога (его инициализация и обработка производится внутри процедуры TExecutor). В него передаются кодированные данные (параметры Code и Info), редактируются, кодируются в строку и выдаются Result'ом. Следует обратить внимание, что если особенность только для чтения, то внутри TExecutor следует это учесть и изменить форму, запрещая редактирование данных. Также TButtonEditor служит для реализации методов. Если метод без параметров, то по клику на кнопке производится выполнение этого метода; если с параметрами - выводится диалоговое окно ввода параметров; если метод возвращает какой-либо результат, то он отображается в заголовке кнопки. В Delphi это реализуется маленькой кнопочкой с тремя точками.
Для создания нового элемента управления следует унаследовать его от TParticulControl и обязательно перекрыть методы GetTypeName, GetParticuls и SetParticul. Быстрое создание новых свойств, методов или событий выполняется с помощью процедур DoProperty, DoMethod и DoEvent. Например:
function TSample.GetTypeName: string; begin Result := 'Некоторый класс'; end; function TSample.GetParticuls: TParticulList; var P: TParticul; begin Result := TParticulList.Create; with Result do begin P := DoProperty('Просто строка', dtString, True, True, FString, '', False); Add(P); P := DoProperty('Ширина', dtInteger, Length(FString) <> 0, True, IntToStr(Width), '', False); Add(P); end; end; procedure TSample.SetParticul(Value: TParticul); begin if Value.Name = 'Просто строка' then FString := Value.Code; if Value.Name = 'Ширина' then Width := StrToInt(Value.Code); end; Теперь свойства отобразятся в Инспекторе на вкладке "Свойства" с заголовками "Просто строка" и "Ширина" (на русском!). При их редактировании выведутся соответствующие редакторы с соответствующими Executor'ами. Обращу внимание, что таким образом могут редактироваться как "реальные" свойства, так и просто поля, а, быть может, и выполнятся процедуры (что-то вроде Get и Set).
Теперь хочу коснуться наследования элементов управления. Как известно, Object Pascal не позволяет осуществлять наследование с ограничением видимости, что послужило причиной создания большого количества Custom'ов в VCL. В языке С++ эта возможность имеется (private-, protected- и public-наследование). Данный Инспектор позволяет производить имитацию private- и public-наследования. Это очень удобно, когда необходимо скрыть "лишние" особенности в потомках.
TPublicSample = class(TSample) ... TPrivateSample = class(TSample) ... implementation ... //наследуем все особенности предка и добавляем свои function TPublicSample.GetParticuls: TParticulList; begin Result := inherited GetParticuls; ... end; //добавляем только свои особенности function TPrivateSample.GetParticuls: TParticulList; begin Result := TParticulList.Create; ... end; Хочу ещё раз обратить внимание, что особенности элемента управления не имеют никакого отношения к реальным свойствам, событиям и методам. Можно обращаться к полям, методам, свойствам любой области видимости (а не только published). То есть, методы GetParticuls и SetParticul - это имитация области published.
В примере Example1 показаны реализация свойств и методов различных элементов управления (о событиях чуть попозже, там есть несколько тонкостей). TRectControl - пример элемента управления, TRoundRectControl - его public-наследник, TEllipticControl - его private-наследник. На форму выведены два TRectControl'а и по одному TRoundRectControl'у и TEllipticControl'у. Кнопка Button1 показывает/скрывает Инспектор.