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

10 delphi

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

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

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

.., StdCtrls, MyButton;
Run Code Online (Sandbox Code Playgroud)

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

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

.., ToolWin, ActnMan, ActnCtrls, ActnMenus, MyMenu;
Run Code Online (Sandbox Code Playgroud)

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

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

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

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

我只是想MyButton, MyMenu;自动添加,而不是所有其他常见的单位名称与它们一起添加.

Rem*_*eau 10

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


NGL*_*GLN 8

TL;博士;

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


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

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

示例:在表单上TDBGrid从单元中删除a时DBGrids,也会Grids添加单元,因为在祖先单元中声明了已发布事件的State参数类型.在设计器中双击该事件会导致添加以下处理程序:TGridDrawStateOnDrawDataCell

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

end;
Run Code Online (Sandbox Code Playgroud)

现在,由于存在TGridDrawState,这个源文件需要知道该Grids单元.

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


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

考虑以下示例单位:

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.
Run Code Online (Sandbox Code Playgroud)

unit AwLabelEx;

interface

uses
  Classes, AwLabel;

type
  TAwLabelEx = class(TAwLabel);

implementation

end.
Run Code Online (Sandbox Code Playgroud)

unit AwReg;

interface

uses
  AwLabel, AwLabelEx;

procedure Register;

implementation

procedure Register;
begin
  RegisterComponents('Samples', [TAwLabel, TAwLabelEx]);
end;
Run Code Online (Sandbox Code Playgroud)

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


如何ISelectionEditor.RequiresUnits为雷米说?

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

unit AwTypes;

interface

type
  TAwLabelStyle = (bsWide, bsTall);

implementation

end.
Run Code Online (Sandbox Code Playgroud)

现在,当您在表单上删除一个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.
Run Code Online (Sandbox Code Playgroud)

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