为什么我的组件会自动将其他单位添加到使用界面?

时间:2013-02-02 09:04:18

标签: delphi

我一直在编写一些自己的自定义组件,其中一些只是从其他组件派生而来,例如TCustomButton,TCustomListBox等。

让我们说我有TMyButton = class(TCustomButton),这是在一个名为MyButton的单元中,我已经将这个组件注册并打包并安装到IDE中。

现在我将创建一个新的空项目并将TMyButton拖放到表单中。当我编译项目时,它会自动将这些单元添加到接口部分:

.., StdCtrls, MyButton;

我当然希望添加MyButton,但希望StdCtrls不是。

这不是那么糟糕,但我的其他一些组件更糟糕,例如一个来自TCustomActionMainMenuBar,当我将其添加到我的表单并编译时,我将添加这些额外的单位:

.., ToolWin, ActnMan, ActnCtrls, ActnMenus, MyMenu;

我想创建自己的组件的一个原因是为了防止在界面部分添加了这么多单元名称,我希望自己绘画并更改默认属性等。

当我将3或4个组件添加到表单时,会自动添加额外的6-10个单元名称,我不希望这种情况发生。

所以我的问题 - 是否可以阻止IDE自动将单元名称添加到接口部分?

事实上,我已经在我自己的组件源的实际使用界面中拥有“不需要的”单元名称,我认为这已经足够了。我的组件知道他们需要哪些单元,那么为什么表单的源文件必须知道/被允许包含这些名称呢?

我只想自动添加MyButton, MyMenu;,而不是要添加所有其他常用单位名称。

4 个答案:

答案 0 :(得分:9)

您的组件可能来自已注册TSelectionEditor派生实现的其他组件(请参阅RegisterSelectionEditor()),这些实现覆盖虚拟TSelectionEditor.RequiresUnits()方法以将所需单元插入{{1条款。执行此操作的一个原因是,这些组件是否定义了依赖于其他单元中的类型的属性/事件。

答案 1 :(得分:8)

<强> TL;博士;

不可能阻止添加这些单位,你不应再关心它了。


  

我的组件知道他们需要哪些单元,那么为什么表单的源文件也必须知道这些名称呢?

你是对是错。当然,如果代码仅限于创建组件,那么只需要声明该组件的单元。运行时和设计时。但是当代码开发出来,并且您希望实现需要来自祖先单元的类型的事件处理程序时,那么您的代码需要uses子句中的那些单元。运行时和设计时。

示例:从表单上的单元TDBGrid中删除DBGrids时,还会添加单元Grids,因为其中包含类型发布的State事件的TGridDrawState参数OnDrawDataCell的声明在祖先单元中声明。在设计器中双击该事件会导致添加以下处理程序:

procedure TForm1.DBGrid1DrawDataCell(Sender: TObject; const Rect: TRect;
  Field: TField; State: TGridDrawState);
begin

end;

现在,由于TGridDrawState的存在,此源文件需要知道Grids单元。

结论:可能有太多的单位用于次要开发,但总有足够的单位用于实施所有已发布的事件。


我做了一些关于它是如何工作的研究。我已经赞成Remy's answer,因为没有它我就不会想到这样做,但他实际上并不完全正确。

考虑以下示例单位:

unit AwLabel;

interface

uses
  Classes, StdCtrls;

type
  TAwLabelStyle = (bsWide, bsTall);

  TAwLabel = class(TLabel)
  private
    FStyle: TAwLabelStyle;
  published
    property Style: TAwLabelStyle read FStyle write FStyle default bsWide;
  end;

implementation

end.

unit AwLabelEx;

interface

uses
  Classes, AwLabel;

type
  TAwLabelEx = class(TAwLabel);

implementation

end.

unit AwReg;

interface

uses
  AwLabel, AwLabelEx;

procedure Register;

implementation

procedure Register;
begin
  RegisterComponents('Samples', [TAwLabel, TAwLabelEx]);
end;

现在,您在表单上放置了TAwLabelEx组件,添加了单位AwLabelAwLabelEx,这会自动发生。不需要特别的参与。 AwLabel类型需要TAwLabelStyle单位。请注意,在这种情况下,它与事件无关。剩下的唯一参数是该类型在组件定义的已发布部分中使用。


雷米告诉我ISelectionEditor.RequiresUnits怎么样?

考虑我们将TAwLabelStyle移到另一个单位:

unit AwTypes;

interface

type
  TAwLabelStyle = (bsWide, bsTall);

implementation

end.

现在,当您在表单上放置TAwLabelTAwLabelEx组件时,AwTypes单元未添加 。引用上一个链接:

  

注意:事件可能会使用其参数之一的类型既不在类单元中也不在其任何祖先单元中。在这种情况下,应该注册实现RequiresUnits的选择编辑器,并将其用于声明事件所需类型的每个单元。

所以,让我们注册一个选择编辑器:

unit AwReg;

interface

uses
  Classes, AwTypes, AwLabel, AwLabelEx, DesignIntf, DesignEditors;

type
  TAwLabelSelectionEditor = class(TSelectionEditor)
  public
    procedure RequiresUnits(Proc: TGetStrProc); override;
  end;

procedure Register;

implementation

procedure Register;
begin
  RegisterComponents('Samples', [TAwLabel, TAwLabelEx]);
  RegisterSelectionEditor(TAwLabel, TAwLabelSelectionEditor);
end;

{ TAwLabelSelectionEditor }

procedure TAwLabelSelectionEditor.RequiresUnits(Proc: TGetStrProc);
begin
  Proc('AwTypes');
end;

end.

现在,在表单上删除TAwLabelTAwLabelEx组件会导致将AwTypes单元添加到uses子句中;

答案 2 :(得分:4)

TCustomActionMainMenuBar的继承树如下所示:

System.Classes.TObject
System.Classes.TPersistent
System.Classes.TComponent
Vcl.Controls.TControl
Vcl.Controls.TWinControl
Vcl.ToolWin.TToolWindow
Vcl.ActnMan.TCustomActionBar
Vcl.ActnCtrls.TCustomActionDockBar
Vcl.ActnMenus.TCustomActionMenuBar
Vcl.ActnMenus.TCustomActionMainMenuBar
Vcl.ActnMenus.TActionMainMenuBar

当您在表单上包含组件时,此树中显示的所有单元都将被绘制到uses子句中。每次保存时都会重新插入。如其他人所说,组件还可以使用Open Tools API包含其他不包含祖先的单元。

答案 3 :(得分:2)

这种情况正在发生,因为组件的祖先正在使用Open Tools API将一些单元添加到uses子句中,其代码如下:

uses
  ToolsAPI;

var
  currentProject: IOTAProject;
begin
  currentProject := GetActiveProject();
  currentProject.AddFile('StdCtrls.pas', True);

您可能还会发现this question有趣。