Rambler's Top100
"Knowledge itself is power"
F.Bacon
Поиск | Карта сайта | Помощь | О проекте | ТТХ  
 Сокровищница
  
 

Фильтр по датам

 
 К н и г и
 
Книжная полка
 
 
Библиотека
 
  
  
 


Поиск
 
Поиск по КС
Поиск в статьях
Яndex© + Google©
Поиск книг

 
  
Тематический каталог
Все манускрипты

 
  
Карта VCL
ОШИБКИ
Сообщения системы

 
Форумы
 
Круглый стол
Новые вопросы

 
  
Базарная площадь
Городская площадь

 
   
С Л С

 
Летопись
 
Королевские Хроники
Рыцарский Зал
Глас народа!

 
  
ТТХ
Конкурсы
Королевская клюква

 
Разделы
 
Hello, World!
Лицей

Квинтана

 
  
Сокровищница
Подземелье Магов
Подводные камни
Свитки

 
  
Школа ОБЕРОНА

 
  
Арсенальная башня
Фолианты
Полигон

 
  
Книга Песка
Дальние земли

 
  
АРХИВЫ

 
 

Сейчас на сайте присутствуют:
 
  
 
Во Флориде и в Королевстве сейчас  08:11[Войти] | [Зарегистрироваться]

Разработка эксперта IDE Delphi 2007 с визуальным наследованием форм и размещением их в репозитории

Сергей Деев
дата публикации 22-09-2008 09:40

Разработка эксперта IDE Delphi 2007 с визуальным наследованием форм и размещением их в репозитории

Постановка задачи

При переходе с Delphi 7 на Delphi 2007 я столкнулся с проблемой разработки эксперта IDE с визуальным наследованием форм и размещением их в репозитории.

Все мои эксперты, написанные под Delphi 7, отказывались работать на Delphi 2007.

Я решил разобраться почему это происходит и написать данную статью.

Частичное решение данной проблемы описано в примере на странице Erik's Open Tools API FAQ and Resources.

Попробуем разобраться в данном примере и написать свой эксперт IDE с визуальным наследованием форм и размещением их в репозитории.

Пример эксперта

Заходим на страницу Erik's Open Tools API FAQ and Resources и скачиваем оттуда пример из раздела «How do I implement a module creator (IOTAModuleCreator/ IOTAFormWizard)?»

Получаем файл GXModuleCreator.

Рассмотрим более подробно данный файл.

Класс TGxModuleCreatorWizard

Как видим, этот класс является наследником от класса TNotifierObject, являющийся одним из основных классов с поддержкой интерфейсов. По сути это и есть наш класс-эксперт.

На первых трех интерфейсах IOTAWizard, IOTARepositoryWizard, IOTARepositoryWizard60 долго останавливаться не буду, т. к. они знакомы программистам по более ранним версиям Delphi.

А вот на интерфейсе IOTARepositoryWizard80 остановлюсь более подробно.

Интерфейс IOTARepositoryWizard80

В разделе «Known bugs in the Delphi 2007 Open Tools API (most also apply to earlier releases):» написано, что для создания и правильного функционирования эксперта репозитория необходимо, чтобы наш эксперт поддерживал этот интерфейс (QC 20898).

Остановимся на функциях данного интерфейса:

function GetPersonality: string;

возвращает строку о персональной секции по умолчанию. Как видим из реализации данной функции, она всегда возвращает константу sDelphiPersonality.

function GetGalleryCategory: IOTAGalleryCategory;

возвращает категорию репозотирия, в которую будет помещен наш эксперт. Как видно из реализации этой функции она возвращает категорию по имени, описанной в константе sCategoryDelphiNewFiles

Класс TGxModuleCreator

Как видим, этот класс является наследником от класса TInterfacedObject, и поддерживает хорошо знакомые по предыдущим версиям Delphi интерфейсы IOTACreator и IOTAModuleCreator TNotifierObject. По сути это класс, который будет отвечать за создание файла нашего модуля (pas) с помощью функции

function NewImplSource(const ModuleIdent, FormIdent, AncestorIdent: string): IOTAFile;

и файла описания формы (dfm) с помощью функции

function NewFormFile(const FormIdent, AncestorIdent: string): IOTAFile;

Процедура регистрации эксперта

Основным отличием процедуры регистрации эксперта является использование метода RegisterPackageWizard, а не RegisterCustomModule как в предыдущих версиях Delphi (раздел «Known bugs in the Delphi 2005 Open Tools API: »).

Создание собственного эксперта

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

Примем, что класс этой самой формы будет называться TBaseForm, а все наследники будут иметь префикс в названии класса TInhForm и порядковый номер.

Начнем работу с создания нового пакета. Зайдем в его опции и установим тип пакета как «DisignTime only» и сохраним данный пакет под именем dtInhFormWizard. Вставим в пакет пустой модуль и добавим к пакету в раздел «Requires» пакет designide. После чего приступим к разработке самого эксперта.

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

Примем что, в дальнейшем мы не будем использовать этих предков в других пакетах, то есть расположим описание всех нужных нам классов после директивы implementation.

Получим следующий код:

unit UInhFormReg;

interface

procedure Register;

implementation

uses
  SysUtils, Classes, Windows, DesignIntf, ToolsApi;

end;

Приступим к нашим классам-предкам

Класс-предок всех экспертов TCustomFormWizard

Описание класса:

{TCustomFormWizard}

  TCustomFormWizard = class(TNotifierObject,
                     IOTAWIzard,
                     IOTARepositoryWizard,
                     IOTARepositoryWizard60,
                     IOTARepositoryWizard80,
                     IOTAProjectWizard)
  protected
    function BaseFormName: String; virtual; abstract;
    function AncestorFormName: String; virtual; abstract;
public
    { IOTANotifier }
    procedure AfterSave;
    procedure BeforeSave;
    procedure Destroyed;
    procedure Modified;
    { IOTAWizard }
    function GetIDString: string;
    function GetName: string;
    function GetState: TWizardState;
    procedure Execute; virtual; abstract;
    { IOTARepositoryWizard }
    function GetAuthor: string;
    function GetComment: string;
    function GetPage: string;
    function GetGlyph: Cardinal;
    {IOTARepositoryWizard60}
    function GetDesigner: string;
    {IOTARepositoryWizard80}
    function GetGalleryCategory: IOTAGalleryCategory;
    function GetPersonality: string;
end;

Реализация методов данного класса ничем не отличается от реализации процедур в примере за исключением методов:

function TCustomFormWizard.GetName: string;
begin
  Result := BaseFormName;
end;

function TCustomFormWizard.GetIDString: string;
begin
  Result := 'TCustomForm.' + BaseFormName + '.Wizard'; 
end;

function TCustomFormWizard.GetComment: string;
begin
  Result := 'Creates a new ' + BaseFormName;
end;

Как видим, они вызывают абстрактный метод

function BaseFormName: String; virtual; abstract;

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

Кроме того следует обратить внимание, что метод

procedure Execute; virtual; abstract;

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

Класс-предок всех экспертов TCustomFormModuleCreator

Описание класса:

{ TCustomFormModuleCreator }

  TCustomFormModuleCreator = class(TInterfacedObject, IOTACreator, IOTAModuleCreator)
  private
    FAncestorFormName: string;
    FBaseFormName : string;
    FClassName : string;
    FUnitIdent : string;
    FFileName : string;
  public
    constructor Create(AncestorFormName, BaseFormName: string); virtual;
    { IOTACreator }
    function GetCreatorType: string;
    function GetExisting: Boolean;
    function GetFileSystem: string;
    function GetOwner: IOTAModule; virtual;
    function GetUnnamed: Boolean;
    { IOTAModuleCreator }
    function GetAncestorName: string;
    function GetImplFileName: string;
    function GetIntfFileName: string;
    function GetFormName: string;
    function GetMainForm: Boolean;
    function GetShowForm: Boolean;
    function GetShowSource: Boolean;
    function NewFormFile(const FormIdent, AncestorIdent: string): IOTAFile; virtual; abstract;
    function NewImplSource(const ModuleIdent, FormIdent, AncestorIdent: string): IOTAFile; virtual; abstract;
    function NewIntfSource(const ModuleIdent, FormIdent, AncestorIdent: string): IOTAFile;
    procedure FormCreated(const FormEditor: IOTAFormEditor);
  end;

Реализация методов данного класса ничем не отличается от реализации процедур в примере за исключением методов:

constructor TCustomFormModuleCreator.Create(AncestorFormName, BaseFormName: string);
begin
  FAncestorFormName := AncestorFormName;
  FBaseFormName := BaseFormName;
end;

function TCustomFormModuleCreator.GetAncestorName: string;
begin
  Result := FAncestorFormName;
end;

function TCustomFormModuleCreator.GetFormName: string;
begin
  Result := FBaseFormName
end;

Следует отметить, что конструктор данного класса

constructor Create(AncestorFormName, BaseFormName: string);

виртуальный, а методы

function NewImplSource(const ModuleIdent, FormIdent, AncestorIdent: string): IOTAFile;

и

function NewImplSource(const ModuleIdent, FormIdent, AncestorIdent: string): IOTAFile;

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

Класс TFormModuleSourceFile для поддержки интерфейса IOTAFile

Описание класса:

{ TFormModuleSourceFile }

  TFormModuleSourceFile = class(TInterfacedObject, IOTAFile)
  private
    FSource: string;
  public
    function GetSource: string;
    function GetAge: TDateTime;
    constructor Create(const Source: string);
  end;

Реализация методов данного класса ничем не отличается от реализации процедур в примере.

Класс-наследник создания модуля основной формы TBaseFormModuleCreator

Описание класса:

{ TBaseFormModuleCreator }

  TBaseFormModuleCreator = class(TCustomFormModuleCreator)
  public
    constructor Create(AncestorFormName, BaseFormName: string); override;
    function NewFormFile(const FormIdent, AncestorIdent: string): IOTAFile; override;
    function NewImplSource(const ModuleIdent, FormIdent, AncestorIdent: string): IOTAFile; override;
  end;

Реализация конструктора класса:

constructor TBaseFormModuleCreator.Create(AncestorFormName,
  BaseFormName: string);
var
  AFileName: String;
begin
  inherited Create(AncestorFormName, BaseFormName);
  (BorlandIDEServices as IOTAModuleServices).GetNewModuleAndClassName(BaseFormName, FUnitIdent, FClassName, FFileName);
  FUnitIdent := 'U' + BaseFormName;
  AFileName := ExtractFilePath(FFileName);
  FFileName := AFileName + FUnitIdent + '.pas';
end;

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

В реализации методов NewFormFile и NewImplSource следует отметить наличие констант с описанием самого модуля и описания формы. Можно было бы записать эти константы в ресурс пакета и доставать их оттуда.

Класс-наследник эксперта TBaseFormModuleWizard

Описание класса:

{ TBaseFormModuleWizard }

  TBaseFormModuleWizard = class(TCustomFormWizard)
  protected
    function BaseFormName: String; override;
    function AncestorFormName: String; override;
  public
    procedure Execute; override;
  end;

Реализация метода Execute:

procedure TBaseFormModuleWizard.Execute;
var
  Module: IOTAModule;
begin
  Module := (BorlandIDEServices as IOTAModuleServices).CreateModule(TBaseFormModuleCreator.Create(AncestorFormName, BaseFormName));
end;

Как видим, в нем просто вызывается конструктор класса создания модуля TBaseFormModuleCreator с передачей в него наименований самой формы и ее предка.

Класс-наследник создания модуля форм-наследников TInhFormCreator

Описание класса:

{ TInhFormCreator }

  TInhFormCreator = class(TCustomFormModuleCreator)
  public
    constructor Create(AncestorFormName, BaseFormName: string); override;
    function NewFormFile(const FormIdent, AncestorIdent: string): IOTAFile; override;
    function NewImplSource(const ModuleIdent, FormIdent, AncestorIdent: string): IOTAFile; override;
  end;

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

В методе NewFormFile в константе описания формы предусматриваем ее наследование

В методе NewImplSource в константе описания модуля предусматриваем ссылку на модуль базовой формы и наследование самой формы.

Класс-наследник эксперта TInhFormModuleWizard

Описание класса:

{ TInhFormModuleWizard }

  TInhFormModuleWizard = class(TCustomFormWizard)
  protected
    function BaseFormName: String; override;
    function AncestorFormName: String; override;
  public
    procedure Execute; override;
  end;

Реализация метода Execute:

procedure TInhFormModuleWizard.Execute;
var
  Module: IOTAModule;
  ActiveProject: IOTAProject;
  I: Integer;
  IsAncestorFormName: Boolean;
begin
  ActiveProject := GetActiveProject;
  if ActiveProject <> nil then
  begin
    IsAncestorFormName := False;
    for I := 0 to ActiveProject.GetModuleCount - 1 do
      with ActiveProject.GetModule(I) do
        if FormName = AncestorFormName then
        begin
          IsAncestorFormName := True;
          Break;
        end;
    if not IsAncestorFormName then
      with TBaseFormModuleWizard.Create do
      try
        Execute;
      finally
        Free;
      end;
    Module := (BorlandIDEServices as IOTAModuleServices).CreateModule(TInhFormCreator.Create(AncestorFormName, BaseFormName));
  end;
end;

Как видим, в методе создается объект типа текущий проект, затем если текущий проект создан в нем ищется базовая форма и если ее не находят, то вызывается конструктор ее эксперта, а затем и создание самого модуля формы-наследницы.

Процедура регистрации эксперта

procedure Register;
begin
  RegisterPackageWizard(TInhFormModuleWizard.Create);
end;

Заключение

Полностью файл проекта можно посмотреть в приложенном файле.

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

При написании статьи использовались материалы со страницы Erik's Open Tools API FAQ and Resources.

Прилагаемые файлы




Смотрите также материалы по темам:
[Репозиторий объектов]

 Обсуждение материала нет сообщений
  
Время на сайте: GMT минус 5 часов

Если вы заметили орфографическую ошибку на этой странице, просто выделите ошибку мышью и нажмите Ctrl+Enter.
Функция может не работать в некоторых версиях броузеров.

Web hosting for this web site provided by DotNetPark (ASP.NET, SharePoint, MS SQL hosting)  
Software for IIS, Hyper-V, MS SQL. Tools for Windows server administrators. Server migration utilities  

 
© При использовании любых материалов «Королевства Delphi» необходимо указывать источник информации. Перепечатка авторских статей возможна только при согласии всех авторов и администрации сайта.
Все используемые на сайте торговые марки являются собственностью их производителей.

Яндекс цитирования