Конференция "Компоненты" » Создание формы из эксперта проекта - как? [D7, WinXP]
 
  • Korney San © (24.03.09 12:10) [0]
    Здравствуйте, уважаемые. Вопрос по экспертам, такой.
    Имеется шаблон плагина и формы настроек.
    Я сделал эксперта (спасибо доброму человеку за исходники, в которые я внимательно смотрел), который генерирует исходники проекта плагина и модуля реализации.
    Но у меня не получается сгенерировать исходники формы.
    Подскажите, пожалуйста, как нужно делать/где почитать.

    Основная проблема как раз в том, что всё это должно быть в одном эксперте.
  • Игорь Шевченко © (24.03.09 18:52) [1]

    > Но у меня не получается сгенерировать исходники формы.


    Я когда-то развлекался, вроде генерируется и .pas и .dfm

    unit TestRepositoryWizard;

    interface
    uses
     Windows, Classes, ToolsApi;

    type
     TTestClassGenerator = class(TInterfacedObject, IOTACreator, IOTAModuleCreator)
     private
       FUnitIdent : String;
       FClassName : String;
     public
       { 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;
       function NewImplSource(const ModuleIdent, FormIdent,
         AncestorIdent : String) : IOTAFile;
       function NewIntfSource(const ModuleIdent, FormIdent,
         AncestorIdent : String) : IOTAFile;
       procedure FormCreated (const FormEditor : IOTAFormEditor);
       { IOTACreator }
       function GetCreatorType: String;
       function GetExisting : Boolean;
       function GetFileSystem : String;
       function GetOwner : IOTAModule;
       function GetUnnamed : Boolean;
       { Собственные методы }
       constructor Create (UnitIdent, ClassName : String); virtual;

       property CreatorType : String read GetCreatorType;
       property Existing : Boolean read GetExisting;
       property FileSystem : String read GetFileSystem;
       property Owner : IOTAModule read GetOwner;
       property Unnamed : Boolean read GetUnnamed;

       property AncestorName : String read GetAncestorName;
       property FormName : String read GetFormName;
       property ImplFileName : String read GetImplFileName;
       property IntfFileName : String read GetIntfFileName;
       property MainForm : Boolean read GetMainForm;
       property ShowForm : Boolean read GetShowForm;
       property ShowSource : Boolean read GetShowSource;
     end;

     TTestFormWizard = class(TNotifierObject, IOTAWizard, IOTARepositoryWizard,
       IOTAFormWizard, IOTACreator, IOTAModuleCreator)
     private
       FUnitIdent : String;
       FFileName : String;
       FClassName : String;
       FTestClassName : String;
       FTestUnitName : String;
     protected
       //Методы класса IOTAWizard
       function GetIDString : String;
       function GetName : String;
       function GetState : TWizardState;
       procedure Execute;
       //Методы классов IOTARepositoryWizard / IOTAFormWizard
       function GetAuthor : String;
       function GetComment : String;
       function GetPage : String;
       function GetGlyph : Cardinal;
       //Методы класса IOTACreator
       function GetCreatorType : String;
       function GetExisting : Boolean;
       function GetFileSystem : String;
       function GetOwner : IOTAModule;
       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;
       function NewImplSource (
         const ModuleIdent, FormIdent, AncestorIdent : String) : IOTAFile;
       function NewIntfSource (
         const ModuleIdent, FormIdent, AncestorIdent : String) : IOTAFile;
       procedure FormCreated (const FormEditor : IOTAFormEditor);
     end;

    procedure Register;

    implementation
    uses
     SysUtils,
     DesignIntf, DesignEditors,
     TestAbstractForm,
     TestClassDlg,
     Controls, Forms;

    {$R CodeGen.res}

    type
     TBaseFile = class(TInterfacedObject)
     private
       FModuleName : String;
       FFormName : String;
       FAncestorName : String;
     public
       constructor Create (const ModuleName, FormName, AncestorName : String);
     end;

     TUnitFile = class(TBaseFile, IOTAFile)
     private
       FTestClassName : String;
       FTestUnitName : String;
     protected
       function GetSource : String;
       function GetAge : TDateTime;
     public
       constructor Create (const ModuleName, FormName, AncestorName,
         TestClassName, TestUnitName : String);
     end;

     TFormFile = class(TBaseFile, IOTAFile)
     protected
       function GetSource : String;
       function GetAge : TDateTime;
     end;

     TTestClassFile = class(TBaseFile, IOTAFile)
     protected
       function GetSource : String;
       function GetAge : TDateTime;
     end;

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




    продолжение следует...
  • Игорь Шевченко © (24.03.09 18:52) [2]
    продолжение

    { TTestFormWizard }

    procedure TTestFormWizard.Execute;
    begin
     with TfTestClassDlg.Create(Application) do
       try
         if ShowModal() <> mrOk then
           Exit;
         FTestClassName := ClassNameEdit.Text;
         FTestUnitName := UnitNameEdit.Text;
       finally
         Free();
       end;
     (BorlandIDEServices as IOTAModuleServices).CreateModule (
       TTestClassGenerator.Create(FTestUnitName, FTestClassName));
     (BorlandIDEServices as IOTAModuleServices).GetNewModuleAndClassName (
        'fAbstractTest', FUnitIdent, FClassName, FFileName);
     (BorlandIDEServices as IOTAModuleServices).CreateModule (Self);
    end;

    procedure TTestFormWizard.FormCreated(const FormEditor: IOTAFormEditor);
    begin
     //Do nothing
    end;

    function TTestFormWizard.GetAncestorName: String;
    begin
     Result := 'TfAbstractTest';
    end;

    function TTestFormWizard.GetAuthor: String;
    begin
     Result := 'Igor Schevchenko';
    end;

    function TTestFormWizard.GetComment: String;
    begin
     Result := 'Creates new Test Suite form';
    end;

    function TTestFormWizard.GetCreatorType: String;
    begin
     Result := '';
    end;

    function TTestFormWizard.GetExisting: Boolean;
    begin
     Result := false;
    end;

    function TTestFormWizard.GetFileSystem: String;
    begin
     Result := '';
    end;

    function TTestFormWizard.GetFormName: String;
    begin
     Result := FClassName;
    end;

    function TTestFormWizard.GetGlyph: Cardinal;
    begin
     Result := 0; //использование стандартной пиктограммы
    end;

    function TTestFormWizard.GetIDString: String;
    begin
     Result := 'TestSuite.NewFormWizard';
    end;

    function TTestFormWizard.GetImplFileName: String;
    var
     CurrDir : array[0..MAX_PATH] of char;
    begin
     //Примечание: требуется полный путь
     GetCurrentDirectory(SizeOf(CurrDir), CurrDir);
     Result := Format('%s\%s%s', [CurrDir, FUnitIdent, '.pas']);
    end;

    function TTestFormWizard.GetIntfFileName: String;
    begin
     Result := '';
    end;

    function TTestFormWizard.GetMainForm: Boolean;
    begin
     Result := false;
    end;

    function TTestFormWizard.GetName: String;
    begin
     Result := 'Test Suite New Form Wizard';
    end;

    function TTestFormWizard.GetOwner: IOTAModule;
    var
     I : Integer;
     ModServ : IOTAModuleServices;
     Module : IOTAModule;
     ProjGrp : IOTAProjectGroup;
    begin
     Result := nil;
     ModServ := BorlandIDEServices as IOTAModuleServices;
     for I:=0 to Pred(ModServ.ModuleCount) do begin
       Module := ModServ.Modules[I];
       //Поиск текущей группы проекта
       if CompareText(ExtractFileExt(Module.FileName), '.bpg') = 0 then
         if Module.QueryInterface (IOTAProjectGroup, ProjGrp) = S_OK then begin
           //Возврат активного проекта группы
           Result := ProjGrp.GetActiveProject;
           Exit;
         end;
     end;
    end;

    function TTestFormWizard.GetPage: String;
    begin
     Result := 'TestSuite';
    end;

    function TTestFormWizard.GetShowForm: Boolean;
    begin
     Result := true;
    end;

    function TTestFormWizard.GetShowSource: Boolean;
    begin
     Result := true;
    end;

    function TTestFormWizard.GetState: TWizardState;
    begin
     Result := [wsEnabled];
    end;

    function TTestFormWizard.GetUnnamed: Boolean;
    begin
     Result := true;
    end;

    function TTestFormWizard.NewFormFile(const FormIdent,
     AncestorIdent: String): IOTAFile;
    begin
     Result := TFormFile.Create('', FormIdent, AncestorIdent);
    end;

    function TTestFormWizard.NewImplSource(const ModuleIdent, FormIdent,
     AncestorIdent: String): IOTAFile;
    begin
     Result := TUnitFile.Create(ModuleIdent, FormIdent, AncestorIdent,
       FTestClassName, FTestUnitName);
    end;

    function TTestFormWizard.NewIntfSource(const ModuleIdent, FormIdent,
     AncestorIdent: String): IOTAFile;
    begin
     Result := nil;
    end;

  • Игорь Шевченко © (24.03.09 18:53) [3]

    { TBaseFile }

    constructor TBaseFile.Create(const ModuleName, FormName,
     AncestorName: String);
    begin
     inherited Create;
     FModuleName := ModuleName;
     FFormName := FormName;
     FAncestorName := AncestorName;
    end;

    { TUnitFile }

    constructor TUnitFile.Create(const ModuleName, FormName, AncestorName,
     TestClassName, TestUnitName: String);
    begin
     inherited Create (ModuleName, FormName, AncestorName);
     FTestClassName := TestClassName;
     FTestUnitName := TestUnitName;
    end;

    function TUnitFile.GetAge: TDateTime;
    begin
     Result := -1;
    end;

    function TUnitFile.GetSource: String;
    var
     Text : String;
     ResInstance : THandle;
     HRes : HRSRC;
    begin
     ResInstance := FindResourceHinstance (HInstance);
     HRes := FindResource(ResInstance, 'CODEGEN', RT_RCDATA);
     Text := PChar(LockResource(LoadResource(ResInstance,HRes)));
     SetLength(Text, SizeOfResource(ResInstance, HRes));
     Result := Format(Text, [FModuleName, FFormName, FAncestorName,
       FTestClassName, FTestUnitName]);
    end;

    { TFormFile }

    function TFormFile.GetAge: TDateTime;
    begin
     Result := -1;
    end;

    function TFormFile.GetSource: String;
    const
     FormText = 'inherited %0:s: T%0:s'#13#10'end';
    begin
     Result := Format(FormText, [FFormName]);
    end;

    { TTestClassGenerator }

    constructor TTestClassGenerator.Create(UnitIdent, ClassName: String);
    begin
     FUnitIdent := UnitIdent;
     FClassName := ClassName;
    end;

    procedure TTestClassGenerator.FormCreated(
     const FormEditor: IOTAFormEditor);
    begin
     //Do nothing
    end;

    function TTestClassGenerator.GetAncestorName: String;
    begin
     Result := ''; //Форма не создается, предка нету
    end;

    function TTestClassGenerator.GetCreatorType: String;
    begin
     Result := '';
    end;

    function TTestClassGenerator.GetExisting: Boolean;
    begin
     Result := false; //Создается новый файл
    end;

    function TTestClassGenerator.GetFileSystem: String;
    begin
     Result := '';
    end;

    function TTestClassGenerator.GetFormName: String;
    begin
     Result := FClassName;
    end;

    function TTestClassGenerator.GetImplFileName: String;
    var
     Buffer : array[0..MAX_PATH] of char;
    begin
     GetCurrentDirectory (SizeOf(Buffer), Buffer);
     Result := Format ('%s\%s.pas', [Buffer, FUnitIdent]);
    end;

    function TTestClassGenerator.GetIntfFileName: String;
    begin
     Result := '';
    end;

    function TTestClassGenerator.GetMainForm: Boolean;
    begin
     Result := false;
    end;

    function TTestClassGenerator.GetOwner: IOTAModule;
    var
     I : Integer;
     ModServ : IOTAModuleServices;
     Module : IOTAModule;
     ProjGrp : IOTAProjectGroup;
     Project : IOTAProject;
    begin
     Result := nil;
     ModServ := BorlandIDEServices as IOTAModuleServices;
     for I:=0 to Pred(ModServ.ModuleCount) do begin
       Module := ModServ.Modules[I];
       if Module.QueryInterface(IOTAProjectGroup, ProjGrp) = S_OK then begin
         Result := ProjGrp.ActiveProject;
         Break;
       end else if Module.QueryInterface(IOTAProject, Project) = S_OK then begin
         Result := Project;
         Break;
       end;
     end;
    end;

    function TTestClassGenerator.GetShowForm: Boolean;
    begin
     Result := false;
    end;

    function TTestClassGenerator.GetShowSource: Boolean;
    begin
     Result := true;
    end;

    function TTestClassGenerator.GetUnnamed: Boolean;
    begin
     Result := false;
    end;

    function TTestClassGenerator.NewFormFile(const FormIdent,
     AncestorIdent: String): IOTAFile;
    begin
     Result := nil;
    end;

    function TTestClassGenerator.NewImplSource(const ModuleIdent, FormIdent,
     AncestorIdent: String): IOTAFile;
    begin
     Result := TTestClassFile.Create(ModuleIdent, FormIdent, AncestorIdent);
    end;

    function TTestClassGenerator.NewIntfSource(const ModuleIdent, FormIdent,
     AncestorIdent: String): IOTAFile;
    begin
     Result := nil;
    end;

    { TTestClassFile }

    function TTestClassFile.GetAge: TDateTime;
    begin
     Result := -1;
    end;

    function TTestClassFile.GetSource: String;
    var
     Text : String;
     ResInstance : THandle;
     HRes : HRSRC;
    begin
     ResInstance := FindResourceHinstance (HInstance);
     HRes := FindResource(ResInstance, 'CLASSGEN', RT_RCDATA);
     Text := PChar(LockResource(LoadResource(ResInstance,HRes)));
     SetLength(Text, SizeOfResource(ResInstance, HRes));
     Result := Format(Text, [FModuleName, FFormName]);
    end;

    end.

  • Игорь Шевченко © (24.03.09 18:53) [4]
    ну и сами ресурсы:

    codegen.rc
    CODEGEN RCDATA codegen.txt
    CLASSGEN RCDATA classgen.txt



    classgen.txt
    unit %0:s;

    interface

    uses
     Windows, Messages, SysUtils, Classes, Forms, TestAbstractTest;

    type
     T%1:s = class (TAbstractTest)
     private
       {Private declarations}
     protected
       {Protected declarations}
       procedure Setup; override;
       procedure TearDown; override;
     public
       procedure RunTests; override;
       {Public declarations}
     end;

    implementation

    procedure T%1:s.RunTests;
    begin
     {TODO: Insert your code here}
    end;

    procedure T%1:s.Setup;
    begin
     {TODO: Insert your code here}
    end;

    procedure T%1:s.TearDown;
    begin
     {TODO: Insert your code here}
    end;

    initialization
     RegisterTestClass(T%1:s);
    end.



    codegen.txt
    unit %0:s;

    interface

    uses
     Windows, Messages, SysUtils, Classes, Forms, TestAbstractForm;

    type
     T%1:s = class (%2:s)
     private
       {Private declarations}
     protected
       {Protected declarations}
     public
       procedure RunTests; override;
       {Public declarations}
     end;

    implementation
    uses
     %4:s;

    {$R *.dfm}

    procedure T%1:s.RunTests;
    var
     TestObject : T%3:s;
    begin
     TestObject := T%3:s.Create(Self);
     try
       TestObject.RunTests();
     finally
       TestObject.Free();
     end;
    end;

    end.

  • Korney San © (25.03.09 13:26) [5]
    Спасибо!
    Старательно всё скопипастил, ушёл экспериментировать.

    О результатах отпишусь.
  • Korney San © (25.03.09 14:13) [6]
    А что должно содержаться в модуле TestAbstractForm ?
  • Игорь Шевченко © (25.03.09 14:32) [7]

    > А что должно содержаться в модуле TestAbstractForm ?


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

    Насколько я понял, проблемы именно с генерацией, а не с воспроизведением моего кода ?
  • Korney San © (25.03.09 16:38) [8]
    Именно так.
    Извиняюсь за копипастинг - я сначала компилировал предоставленный исходник (первоначальный, теперь Ваш), потом, меняя его текст, анализировал происходящие изменения в выдаче.
    Я догадался включить в ресурсы текст своей формы.
    Сейчас я переделал Ваш код так:

    TDMFormWizard = class(TNotifierObject, IOTAWizard, IOTARepositoryWizard,
      IOTAFormWizard, IOTACreator, IOTAModuleCreator)
    private
      {
      FUnitIdent : String;
      FFileName : String;
      FClassName : String;
      }

      FTestClassName : String;
      FTestUnitName : String;
      FOptions:TDMPluginWizardOptions;
    protected
      //&#204;&#229;&#242;&#238;&#228;&#251; &#234;&#235;&#224;&#241;&#241;&#224; IOTAWizard
      function GetIDString : String;
      function GetName : String;
      function GetState : TWizardState;
      procedure Execute; overload;
      procedure Execute(Options: TDMPluginWizardOptions); overload;
      //&#204;&#229;&#242;&#238;&#228;&#251; &#234;&#235;&#224;&#241;&#241;&#238;&#226; IOTARepositoryWizard / IOTAFormWizard
      function GetAuthor : String;
      function GetComment : String;
      function GetPage : String;
      function GetGlyph : Cardinal;
      //&#204;&#229;&#242;&#238;&#228;&#251; &#234;&#235;&#224;&#241;&#241;&#224; IOTACreator
      function GetCreatorType : String;
      function GetExisting : Boolean;
      function GetFileSystem : String;
      function GetOwner : IOTAModule;
      function GetUnnamed : Boolean;
      //&#204;&#229;&#242;&#238;&#228;&#251; &#234;&#235;&#224;&#241;&#241;&#224; 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;
      function NewImplSource (
        const ModuleIdent, FormIdent, AncestorIdent : String) : IOTAFile;
      function NewIntfSource (
        const ModuleIdent, FormIdent, AncestorIdent : String) : IOTAFile;
      procedure FormCreated (const FormEditor : IOTAFormEditor);
    end;

     // creates implementation file
     TFormFile = class(TInterfacedObject, IInterface, IOTAFile)
     private
       FOptions:TDMPluginWizardOptions;
     public
       function GetAge:TDateTime;
       function GetSource:string;
       constructor Create(Options:TDMPluginWizardOptions; const FormIdent:string);
     end;


    ...
  • Korney San © (25.03.09 16:39) [9]
    ...и реализация

    { TDMFormWizard }

    procedure TDMFormWizard.Execute;
    begin
    {
    with TfTestClassDlg.Create(Application) do
      try
        if ShowModal() <> mrOk then
          Exit;
        FTestClassName := ClassNameEdit.Text;
        FTestUnitName := UnitNameEdit.Text;
      finally
        Free();
      end;
    (BorlandIDEServices as IOTAModuleServices).CreateModule (
      TTestClassGenerator.Create(FTestUnitName, FTestClassName));
    (BorlandIDEServices as IOTAModuleServices).GetNewModuleAndClassName (
       'fAbstractTest', FUnitIdent, FClassName, FFileName);
    }

    (BorlandIDEServices as IOTAModuleServices).CreateModule (Self);
    end;

    procedure TDMFormWizard.Execute(Options: TDMPluginWizardOptions);
    begin
    FOptions:=Options;
    (BorlandIDEServices as IOTAModuleServices).CreateModule (Self);
    end;

    procedure TDMFormWizard.FormCreated(const FormEditor: IOTAFormEditor);
    begin
    //Do nothing
    end;

    function TDMFormWizard.GetAncestorName: String;
    begin
    //Result := 'TfAbstractTest';
    Result := 'TForm';
    end;

    function TDMFormWizard.GetAuthor: String;
    begin
    Result := 'Alexander Kornienko';
    end;

    function TDMFormWizard.GetComment: String;
    begin
    Result := 'Creates new Download Master plugin''s setup form';
    end;

    function TDMFormWizard.GetCreatorType: String;
    begin
    Result := '';
    end;

    function TDMFormWizard.GetExisting: Boolean;
    begin
    Result := false;
    end;

    function TDMFormWizard.GetFileSystem: String;
    begin
    Result := '';
    end;

    function TDMFormWizard.GetFormName: String;
    begin
    //Result := FClassName;
    Result:=FOptions.FormName;
    end;

    function TDMFormWizard.GetGlyph: Cardinal;
    begin
    Result := 0; //&#232;&#241;&#239;&#238;&#235;&#252;&#231;&#238;&#226;&#224;&#237;&#232;&#229; &#241;&#242;&#224;&#237;&#228;&#224;&#240;&#242;&#237;&#238;&#233; &#239;&#232;&#234;&#242;&#238;&#227;&#240;&#224;&#236;&#236;&#251;
    end;

    function TDMFormWizard.GetIDString: String;
    begin
    Result := 'DownloadMaster.SetupFormWizard';
    end;

    function TDMFormWizard.GetImplFileName: String;
    {
    var
    CurrDir : array[0..MAX_PATH] of char;
    }

    begin
    //&#207;&#240;&#232;&#236;&#229;&#247;&#224;&#237;&#232;&#229;: &#242;&#240;&#229;&#225;&#243;&#229;&#242;&#241;&#255; &#239;&#238;&#235;&#237;&#251;&#233; &#239;&#243;&#242;&#252;
    {
    GetCurrentDirectory(SizeOf(CurrDir), CurrDir);
    Result := Format('%s\%s%s', [CurrDir, FUnitIdent, '.pas']);
    }

    Result:='';
    end;

    function TDMFormWizard.GetIntfFileName: String;
    begin
    Result := '';
    end;

    function TDMFormWizard.GetMainForm: Boolean;
    begin
    Result := false;
    end;

    function TDMFormWizard.GetName: String;
    begin
    Result := 'Download Master Setup Form Wizard';
    end;

    function TDMFormWizard.GetOwner: IOTAModule;
    var
    I : Integer;
    ModServ : IOTAModuleServices;
    Module : IOTAModule;
    ProjGrp : IOTAProjectGroup;
    begin
    Result := nil;
    ModServ := BorlandIDEServices as IOTAModuleServices;
    for I:=0 to Pred(ModServ.ModuleCount) do begin
      Module := ModServ.Modules[I];
      //&#207;&#238;&#232;&#241;&#234; &#242;&#229;&#234;&#243;&#249;&#229;&#233; &#227;&#240;&#243;&#239;&#239;&#251; &#239;&#240;&#238;&#229;&#234;&#242;&#224;
      if CompareText(ExtractFileExt(Module.FileName), '.bpg') = 0 then
        if Module.QueryInterface (IOTAProjectGroup, ProjGrp) = S_OK then begin
          //&#194;&#238;&#231;&#226;&#240;&#224;&#242; &#224;&#234;&#242;&#232;&#226;&#237;&#238;&#227;&#238; &#239;&#240;&#238;&#229;&#234;&#242;&#224; &#227;&#240;&#243;&#239;&#239;&#251;
          Result := ProjGrp.GetActiveProject;
          Exit;
        end;
    end;
    end;

    function TDMFormWizard.GetPage: String;
    begin
    //Result := 'TestSuite';
    Result := 'DownloadMaster';
    end;

    function TDMFormWizard.GetShowForm: Boolean;
    begin
    Result := true;
    end;

    function TDMFormWizard.GetShowSource: Boolean;
    begin
    Result := true;
    end;

    function TDMFormWizard.GetState: TWizardState;
    begin
    Result := [wsEnabled];
    end;

    function TDMFormWizard.GetUnnamed: Boolean;
    begin
    //Result := true;
    Result:=false;
    end;

    function TDMFormWizard.NewFormFile(const FormIdent,
    AncestorIdent: String): IOTAFile;
    begin
    //Result := TFormFile.Create('', FormIdent, AncestorIdent);
    Result := TFormFile.Create(Foptions , FormIdent);
    end;

    function TDMFormWizard.NewImplSource(const ModuleIdent, FormIdent,
    AncestorIdent: String): IOTAFile;
    begin
    {
    Result := TUnitFile.Create(ModuleIdent, FormIdent, AncestorIdent,
      FTestClassName, FTestUnitName);
    }

    Result := nil;
    end;

    function TDMFormWizard.NewIntfSource(const ModuleIdent, FormIdent,
    AncestorIdent: String): IOTAFile;
    begin
    Result := nil;
    end;

    { TFormFile }

    constructor TFormFile.Create(Options:TDMPluginWizardOptions; const FormIdent:string);
    begin
     FOptions := Options;
     FOptions.FormName := FormIdent;
    end;

    function TFormFile.GetAge:TDateTime;
    begin
     Result := -1;
    end;

    function TFormFile.GetSource:string;
    begin
     Result := LoadResourceText('PLUGINFORMUNIT');
     Result := ReplaceMacros(Result, FOptions);
    end;


    В другом эксперте я создаю экземпляр TDMFormWizard, затем вызываю его Execute - и получаю AV read of address 00000000
  • Korney San © (25.03.09 16:55) [10]
    Возможно, я недостаточно точно очертил задачу.
    В одном эксперте требуется:
    1. Создать исходный текст проекта (library xxxx, dpr)
    2. Создать исходный текст модуля реализации (unit xxxx_Impl, pas)
    3. Создать исходный текст формы (unit xxxx_SetupForm, pas&dpr)
    В качестве бонуса на форме лежат два BitButton (OK и Cancel).
  • Игорь Шевченко © (25.03.09 17:39) [11]
    Korney San ©   (25.03.09 16:55) [10]

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

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

    Я не совсем понимаю другое - эксперт, насколько я понимаю, нужен, чтобы генерировать код по шаблону с параметрами, причем, такими параметрами, которые непосредственно влияют на сам код (имена классов, еще что-нибудь, верятно, логика работы).

    А для генерации цельного проекта - а, если не секрет, что именно там параметризуется ?
  • Korney San © (25.03.09 18:01) [12]
    Параметризуется следующее:
    1. Имя проекта (оно же <имя файла проекта>.dpr, <имя файла модуля>_Impl.pas, <имя файла формы>SetupForm.pas/.dfm)
    2. Класс плагина (он же <класс формы>SetupForm)
    Остальные подстановки - чисто замена шаблонов в исходниках заполненным текстом, поэтому я их здесь не привожу.
    Шаблон исходного кода для .dpr и .pas зашил в ресурсы, как в примерах.
    На текущий момент я добился того, что у меня:
    1. Создаётся .dpr с заданным именем файла и "правильным" исходным текстом.
    2. Создаётся .pas модуля с заданным именем файла и "правильным" исходным текстом.
    3. Всё это открывается в IDE.
    Хочется ещё создать и файл исходного текста формы с соответствующим .dfm .
    Следуя исходным текстам эксперта - достаточно было бы ещё одного IOTAModuleCreator, но кто тогда создаст .dfm ?

    P.S. Ваш откомпилированный эксперт создаёт и открывает форму... Завидно...
  • Игорь Шевченко © (25.03.09 18:22) [13]
    Korney San ©   (25.03.09 18:01) [12]

    Насколько я вспоминаю, каждый модуль создается вызовом
    (BorlandIDEServices as IOTAModuleServices).CreateModule

    у меня таких вызовов два, одним создается форма, другим создается дополнительный модуль - у меня эксперт создает три файла, два .pas и один .dfm

    Я к чему - может, следует вызывать CreateModule столько раз, сколько модулей надо получить ?
  • Korney San © (26.03.09 16:11) [14]
    Вы не поверите! После вашего совета я всё-таки справился с этой задачкой! Немного ковыряния в справке, и вот оно:

    type
     TFormCreator = class(TInterfacedObject, IInterface, IOTACreator, IOTAModuleCreator)
     private
       FOwner:IOTAModule;
       FOptions:TDMPluginWizardOptions;
     public
       procedure FormCreated(const FormEditor:IOTAFormEditor);
       function GetAncestorName:string;
       function GetCreatorType:string;
       function GetExisting:Boolean;
       function GetFileSystem:string;
       function GetFormName:string;
       function GetImplFileName:string;
       function GetIntfFileName:string;
       function GetMainForm:Boolean;
       function GetOwner:IOTAModule;
       function GetShowForm:Boolean;
       function GetShowSource:Boolean;
       function GetUnnamed:Boolean;
       function NewFormFile(const FormIdent:string;
         const AncestorIdent:string):IOTAFile;
       function NewImplSource(const ModuleIdent:string;
         const FormIdent:string; const AncestorIdent:string):IOTAFile;
       function NewIntfSource(const ModuleIdent:string;
         const FormIdent:string; const AncestorIdent:string):IOTAFile;
       constructor Create(const Owner:IOTAModule; Options:TDMPluginWizardOptions);
     end;

     TFormImpl = class(TInterfacedObject, IInterface, IOTAFile)
     private
       FOptions:TDMPluginWizardOptions;
     public
       function GetAge:TDateTime;
       function GetSource:string;
       constructor Create(Options:TDMPluginWizardOptions; const FormIdent:string);
     end;

    { TFormCreator }

    constructor TFormCreator.Create(const Owner:IOTAModule; Options:TDMPluginWizardOptions);
    begin
     FOwner := Owner;
     FOptions := Options;
    end;

    procedure TFormCreator.FormCreated(const FormEditor:IOTAFormEditor);
    var
     Container: IOTAComponent;
    begin
    //
    Container:=nil;
    FormEditor.CreateComponent(nil, 'TBitBtn', 96, 200, 75, 25);
    FormEditor.CreateComponent(nil, 'TBitBtn', 280, 200, 75, 25);
    end;

    function TFormCreator.GetAncestorName:string;
    begin
     Result := '';
    end;

    function TFormCreator.GetCreatorType:string;
    begin
     Result:=sForm; //вот где собака порылась!!!
    end;

    function TFormCreator.GetExisting:Boolean;
    begin
     Result := false;
    end;

    function TFormCreator.GetFileSystem:string;
    begin
     Result := '';
    end;

    function TFormCreator.GetFormName:string;
    begin
     Result:=Copy(FOptions.FormClassName, 2, 255); //отрезаем T от имени класса формы ;)
    end;

    function TFormCreator.GetImplFileName:string;
    begin
     Result:=FOptions.FormUnitName+'.pas';
    end;

    function TFormCreator.GetIntfFileName:string;
    begin
     Result := '';
    end;

    function TFormCreator.GetMainForm:Boolean;
    begin
     Result := false;
    end;

    function TFormCreator.GetOwner:IOTAModule;
    begin
     Result := FOwner;
    end;

    function TFormCreator.GetShowForm:Boolean;
    begin
     Result := true;
    end;

    function TFormCreator.GetShowSource:Boolean;
    begin
     Result := true;
    end;

    function TFormCreator.GetUnnamed:Boolean;
    begin
     Result:=false;
    end;

    function TFormCreator.NewFormFile(const FormIdent, AncestorIdent:string):IOTAFile;
    begin
     Result := nil;
    end;

    function TFormCreator.NewImplSource(const ModuleIdent, FormIdent, AncestorIdent:string):IOTAFile;
    begin
     Result := TFormImpl.Create(FOptions, FormIdent);
    end;

    function TFormCreator.NewIntfSource(const ModuleIdent, FormIdent,
     AncestorIdent:string):IOTAFile;
    begin
     Result := nil;
    end;

    { TFormImpl }

    constructor TFormImpl.Create(Options:TDMPluginWizardOptions; const FormIdent:string);
    begin
     FOptions := Options;
     FOptions.FormUnitName := FormIdent;
    end;

    function TFormImpl.GetAge:TDateTime;
    begin
     Result := -1;
    end;

    function TFormImpl.GetSource:string;
    begin
     Result := LoadResourceText('PLUGINFORMUNIT');
     Result := ReplaceMacros(Result, FOptions);
    end;


    Теперь мне осталось узнать, как изменить свойства полученной формы (в частности, BorderType) и повесить на созданные кнопки обработчики, прописанные в тексте...
  • Korney San © (26.03.09 17:12) [15]
    Разобрался, как изменять свойства созданной формы:

    procedure TFormCreator.FormCreated(const FormEditor:IOTAFormEditor);
    var
     OContainer: IOTAComponent;
     NContainer: INTAComponent;
     Component: TComponent;
    procedure RefClean;
    begin
     Component:=nil;
     NContainer:=nil;
     OContainer:=nil;
    end;
    begin
    //form setup
    RefClean;
    OContainer:=FormEditor.GetRootComponent;
    OContainer.QueryInterface(INTAComponent, NContainer);
    Component:=NContainer.GetComponent;
    (Component as TForm).BorderStyle:=bsSingle;
    (Component as TForm).Caption:='frmSetupForm';
    (Component as TForm).ClientHeight:=250;
    (Component as TForm).ClientWidth:=457;
    (Component as TForm).Position:=poMainFormCenter;
    //BitBtn1 setup
    RefClean;
    OContainer:=FormEditor.CreateComponent(nil, 'TBitBtn', 96, 200, 75, 25);
    OContainer.QueryInterface(INTAComponent, NContainer);
    Component:=NContainer.GetComponent;
    (Component as TBitBtn).Kind:=bkOk;
    //BitBtn2 setup
    RefClean;
    OContainer:=FormEditor.CreateComponent(nil, 'TBitBtn', 280, 200, 75, 25);
    OContainer.QueryInterface(INTAComponent, NContainer);
    Component:=NContainer.GetComponent;
    (Component as TBitBtn).Kind:=bkCancel;
    //end
    RefClean;
    end;


    Остался последний вопрос - как назначить/связать с названием, указанным в тексте шаблона, обработчик события, к примеру, OnCreate формы?
  • Игорь Шевченко © (26.03.09 18:31) [16]

    > Остался последний вопрос - как назначить/связать с названием,
    >  указанным в тексте шаблона, обработчик события, к примеру,
    >  OnCreate формы?


    Я бы при генерации задавал, генерируется же простой текстовый файл, как .dfm, так и .pas, и я полагаю, что при открытии сгенерированного файла происходит точно такой же его синтаксический разбор, как и при обычном открытии.
  • Korney San © (27.03.09 14:29) [17]
    Ээээ... а как оно собразит такой код

    (Component as TForm).OnCreate:=%formclass%.FormCreate;


    ?
  • Korney San © (27.03.09 14:32) [18]
    Я в том смысле, что эксперт на момент компиляции ещё не знает, что у некого (Component as TForm) есть привнесённый FormCreate.
    Как компилятор будет разбираться с этой ситуацией?
  • Игорь Шевченко © (27.03.09 17:43) [19]
    Korney San ©   (27.03.09 14:32) [18]

    Я немного другое имел в виду. Эскперт генерирует текстовые файлы - вот пусть он их и сгенерирует вместе с событием. То есть, назначать событие не во время работы эксперта, а во время генерации кода, в самом шаблоне.
  • Korney San © (31.03.09 16:06) [20]
    Вы упускаете из виду, что как минимум одно событие должно быть назначено "вживую", для того, чтобы поназначать остальные события.
    Например, генерируется:

    procedure TForm.FormCreate;
    begin
    OnDestroy:=FormDestroy;
    end;

    procedure TForm.FormDestroy;
    begin
    //bla bla bla
    end;


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

    Или я что-то упускаю?
  • Игорь Шевченко © (31.03.09 18:16) [21]
    Вот у меня в эксперте есть генерация формы:

    function TFormFile.GetSource: String;
    const
    FormText = 'inherited %0:s: T%0:s'#13#10'end';
    begin
    Result := Format(FormText, [FFormName]);
    end;



    если я FormText заменю на

    inherited %0:s: T%0:s'#13#10'   OnCreate = FormCreate end';

    а в генерируемом тексте добавлю

    type
     T%1:s = class (%2:s)
       procedure FormCreate (Sender: TObject);
     private
       {Private declarations}
     protected
       {Protected declarations}
     public
       procedure RunTests; override;
       {Public declarations}
     end;



    и, соответственно, реализацию, разве этого не будет достаточно ?
  • Korney San © (17.04.09 15:21) [22]
    Спасибо, Вы всё-таки толкнули меня на правильный путь. Я разобрался и сделал следующее:

     // creates source file
     TFormFile = class(TInterfacedObject, IInterface, IOTAFile)
     private
      FOptions:TDMPluginWizardOptions;
     protected
       function GetSource : String;
       function GetAge : TDateTime;
     public
       constructor Create(Options:TDMPluginWizardOptions);
     end;

    function TFormCreator.NewFormFile(const FormIdent, AncestorIdent:string):IOTAFile;
    begin
     //Result := nil;
     Result:= TFormFile.Create(FOptions);
    end;

    { TFormFile }

    constructor TFormFile.Create(Options:TDMPluginWizardOptions);
    begin
     FOptions := Options;
    end;

    function TFormFile.GetAge: TDateTime;
    begin
    Result := -1;
    end;

    function TFormFile.GetSource: String;
    const
    FormText = 'inherited %0:s: %1:s'#13#10'OnCreate = FormCreate'#13#10'end';
    begin
    Result := Format(FormText, [Copy(FOptions.FormClassName, 2, 255), FOptions.FormClassName]);
    end;


    Форма генерируется с прописанным свойством OnCreate.
    Для меня данная тема завершена успешно.

    Огромное Вам спасибо! Надеюсь, озвученные здесь Ваши подсказки и мой опыт помогут избежать подобных "граблей" кому-то ещё... ;)
 
Конференция "Компоненты" » Создание формы из эксперта проекта - как? [D7, WinXP]
Есть новые Нет новых   [134466   +3][b:0][p:0.021]