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

Delphi 为什么我的组件会自动将其他单位添加到uses界面?,delphi,Delphi,我一直在编写自己的一些自定义组件,其中一些只是从其他组件(如TCustomButton、TCustomListBox等)派生而来 假设我有TMyButton=class(TCustomButton),这是一个名为MyButton的单元,我已经在一个打包的组件中注册了这个组件,并安装到IDE中 现在,我将创建一个新的空项目,并将一个TMyButton放到表单中。当我编译项目时,它会自动将以下单位添加到接口部分: .., StdCtrls, MyButton; 我当然希望添加我的按钮,但希望Std

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

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

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

.., StdCtrls, MyButton;
我当然希望添加我的按钮,但希望StdCtrls没有添加

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

.., ToolWin, ActnMan, ActnCtrls, ActnMenus, MyMenu;
我想创建自己的组件的原因之一是为了防止在接口部分添加太多的单元名称,我想自己绘制并更改它们的默认属性等

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

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

事实上,在我自己的组件源的实际使用接口中,我已经有了“不需要的”单元名称,我认为这已经足够了。我的组件知道它们需要哪些单位,那么为什么表单的源文件也需要知道/允许包含名称呢


我只想要
MyButton,MyMenu
自动添加,而不是所有其他要添加的通用单元名称。

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

uses
  ToolsAPI;

var
  currentProject: IOTAProject;
begin
  currentProject := GetActiveProject();
  currentProject.AddFile('StdCtrls.pas', True);
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

您可能也会发现有趣的情况。

您的组件很可能是从其他组件派生的,这些组件已经注册了
TSelectionEditor
派生的实现(请参阅
RegisterSelectionEditor()
),这些实现覆盖了虚拟
TSelectionEditor.requireUnits()
将所需单位插入
的方法使用
子句。这样做的一个原因是,如果这些组件定义的属性/事件依赖于这些其他单元中的类型。

TcustomActionMain菜单栏的继承树如下所示:

uses
  ToolsAPI;

var
  currentProject: IOTAProject;
begin
  currentProject := GetActiveProject();
  currentProject.AddFile('StdCtrls.pas', True);
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子句中,并且每次保存时都会重新插入。组件还可以像其他人所说的那样,通过使用开放工具API包括不包含祖先的其他单元。

tl;博士

不可能阻止添加这些单元,您不应该再关心它


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

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

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

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

end;
现在,由于存在
TGridDrawState
,此源文件需要知道
网格
单元

结论:可能有太多的单元用于次要开发,但总是有足够的单元用于执行所有已发布的事件


我做了一点研究,看看这到底是怎么回事。我已经投了赞成票,因为如果没有它,我不会想到这样做,但他实际上并不完全正确

考虑以下示例单元:

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.

现在,如果将
TAwLabelEx
组件放到表单上,就会添加单位
AwLabel
AwLabelEx
,这会自动发生。不需要特别参与。
TAwLabelStyle
类型需要
AwLabel
单元。请注意,它与本例中的事件无关。剩下的唯一参数是该类型在组件定义的已发布部分中使用


如雷米所说的那样

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

unit AwTypes;

interface

type
  TAwLabelStyle = (bsWide, bsTall);

implementation

end.
现在将
TAwLabel
TAwLabelEx
组件放到表单上时,不会添加
AwTypes
单元。引用上一个链接:

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

那么,让我们注册一个选择编辑器:

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.

现在,在表单上删除
TAwLabel
TAwLabelEx
组件会导致在uses子句中添加
AwTypes
单元

我认为它们需要添加,因为您的组件依赖于它们-如果您手动删除这些单元,它会工作吗?它还会编译吗?@Jeff如果我删除它们,它们会在下一次编译时返回。事实上,这些单元已经在我的组件源中,我认为这就足够了