Delphi表单继承,可视化bug

时间:2015-06-08 08:44:12

标签: forms delphi

我在delphi中遇到这个错误,我从不同的形式(总共3个)中进行了预测,当我创建最后一个孩子时,它会创建每个组件3次。它的dll项目和dll使用不同的形式。我有一个用于测试dll的启动器。在调用创建所需表单的函数时,它会在一个窗口中创建所有3个(下面的屏幕)。我试过给我的组件命名相同。它没有显示编译dll时的任何错误,但是在从启动器调用该函数时它表示该组件或该组件已经存在,因此我必须为所有组件提供不同的名称。 (如果不清楚,请向我提问,我不知道如何更清楚地解释它)

以下是我的表单定义:

  TFrmReserve007 = class(TfrmRsrvExtended)
  private
    { Private declarations }
    [...]
  protected
    { Protected declarations }
    [...]
  public
    { Public declarations }
    [...]
  end;

TfrmRsrvExtended = class(TfrmRsrv)
    Act_Browse2: TAction;
    Act_SaveAs2: TAction;
    Act_LoadDefault2: TAction;
    ImageListToolbar2: TImageList;
    PSCMandatoryObjects2: TPSCMandatoryObjects;
    ImageListMouvement2: TImageList;
    [...More components...]
    TopPanel2: TPSCTopPanel;
    procedure Act_BrowseExecute(Sender: TObject);
    procedure Act_LoadDefaultExecute(Sender: TObject);
    procedure Act_loadSenderExecute(Sender: TObject);
    procedure bbtn_Browse2Click(Sender: TObject);
  private
    { Private declarations }
    [...]
  protected
    [...]
  public
    { Public declarations }
    [...]
  end;

TFrmRsrv = class(TForm)
    PSCButtonPanel1: TPSCButtonPanel;
    PageControl: TPageControl;
    TabSheeta: TTabSheet;
    [.. More components...]
    Act_LoadKeyWord1: TAction;
    Act_LoadStorage1: TAction;
    Mandatory1: TPSCMandatoryObjects;
    PSCHint: TPSCHint;
    {$ENDREGION}
  private
    { Private declarations }
  protected
    { Protected declarations }
    [...]
  public
    { Public declarations }
    [...]
  end;

这意味着那里有功能和程序。

这是我使用TFrmReserve007.Create(nil)

调用表单时的屏幕

enter image description here

MCVE

LAUNCHER

procedure setLXCom;
begin
  if lxPom59Svc = nil then
  begin
    ClassID := ContractIDToClassID('pom59PumaToRio@dtad');
    IU := CreateLynxObject( ClassID);

    if IU = Nil then begin
      raise Exception.Create( 'CreateLynxObject failed');
    end;

    IU.QueryInterface( Ipom59Svc, lxPom59Svc);

    if lxPom59Svc = nil then
    begin
      raise Exception.Create( 'QueryInterface ILynxRio failed');
    end;
  end;
end;

procedure TForm1.Button11Click(Sender: TObject);
begin
  setLxCom;
  lxPom59Svc.RioSvcGui007V2(
  LxPom59Svc.RioGetDataPCE007V2('9051','2010010281',false),lgFRENCH)
end;

DLL

function tl_pom59Svc.RioSvcGui007V2(
  Info: IInfoNotisReservation;For007:boolean;Extension:string; ParentWindow: HWND)
  : IInfoNotisReservation;
var
   Ok : Boolean;
   untKey: String;
   canSave : Boolean;
begin
  Ok := False;
  GetRioDB(fRegister);
  untKey  :=  RioN.GetRegisterByID(RioN.RegisterID, FLAG_IGNORE_SECURITY).Data.UnitID.Value;
  canSave :=  RioN.GetPieceAccess(info.pieceID).Edit;

    While Not(Ok) do
      begin
        Ok := true;
        case LoadFRM_ReservationMod007(Info,
        fRegister, UntKey, canSave, For007, Extension,Parentwindow) of
          TR_Ok :
            begin
              Result := Info;
            end;
          TR_Cancel :
            begin
              Result := Nil;
            end;
          else
            Result := Nil;
        end;
      end;

end;

Function LoadFrm_ReservationMod007(var InfoReservation : IInfoNotisReservation;
               Reg_Key,Unt_Key:string;CanSave:Boolean;For007:boolean;Extension:string; ParentWindow: HWND):TTrilean;
var
  Frm_ReservMod007: TFrmReserve007;
begin

  Frm_ReservMod007 := TFrmReserve007.Create(nil);
  FRM_ReservMod007.ShowModal;    
  if Frm_ReservMod007.ModalResult <> Mrcancel then
      begin
        InfoReservation.Assign(Frm_ReservMod007.InfoReserv);
        Result := TR_Ok;
      end
    else
      begin
         InfoReservation := Nil;
         Result := TR_Cancel;
      end;

end;

1 个答案:

答案 0 :(得分:2)

听起来这就是你所做的 - 让我猜测重现这个问题的步骤:

  1. 创建了一个基本的常规表单 - 我们称之为TForm1
  2. TForm1
  3. 添加了许多控件
  4. 创建了第二个常规表单 - 我们称之为TForm2
  5. 然后,您修改了包含.pas的{​​{1}}文件,使其继承自TForm2(即:TForm1
  6. 您发现TForm2 = class(TForm1)未包含TForm2中的任何控件,即使您“继承了”TForm1
  7. 因此,您将控件从TForm1设计器复制并粘贴到TForm1设计师。
  8. 这会创建一个运行时错误,指示已存在具有相同名称的控件。 (不是猜测 - 你表明了这一点)
  9. 然后你以后代的形式重命名了所有重复的控件(不是猜测 - 你说明了这一点)
  10. 现在,您已经在运行时将基本表单中的所有控件PLUS复制并粘贴(和重命名)的所有控件都添加到后代表单中。然而,后代形式的表单设计器在设计时不显示任何祖先控件 - 只显示您粘贴的新控件。
  11. 这是使用可视化设计器创建继承表单的错误方法。

    要创建包含设计时编辑的继承表单,您必须选择

      

    档案 - &gt;新 - &gt;其他...

    从那里,(这取决于Delphi版本,但对于任何合理的现代......),你选择

      

    Delphi项目 - &gt;可继承的项目 - &gt; Form1中

    TForm2是您希望继承的基本表单。这应该生成一个新单元,其表单继承了基本表单的类代码以及 Form1。如果你看一下创建错误方式的表单中的DFM文件(作为文本 - 推送.dfm),你会看到顶部:

    Alt+F12

    如果你正确地继承(如上所述),你会看到 object Form2: TForm2 ...[etc] 文件的开头为:

    .dfm

    或者,您可以创建常规表单并修改类型声明以从基本表单继承:

     inherited Form2: TForm2
       ...[etc]
    

    您还必须确保将 TForm2 = class(TForm1) ...[etc] 文件从.dfm修改为object。这可以确保表单设计者正确导入属于祖先表单的控件。

    这里的教训是,设计时表单包含两个关键代码。

    1. inherited文件
    2. 中的类代码
    3. .pas文件
    4. 中的组件设计和布局信息

      这里的错误是您只继承了类代码(功能),但没有继承设计和布局信息(内容)。