12

我一直在写一些我自己的自定义组件,一些只是从其他组件中派生而来,例如 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

4 回答 4

10

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

于 2013-02-02T10:45:21.580 回答
8

tl;博士;

无法阻止添加这些单位,您不应再关心它。


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

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

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

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

end;

现在,由于 的存在TGridDrawState,这个源文件需要知道Grids单位。

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


我对它的实际工作原理做了一些研究。我已经赞成Remy 的回答,因为没有它我不会想到这样做,但他实际上并不完全正确。

考虑以下示例单位:

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在表单上放置一个组件,就会添加单元AwLabel和单元AwLabelEx,这会自动发生。不需要特别的参与。该类型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.

现在在表单上删除TAwLabelorTAwLabelEx组件确实会导致将AwTypes单元添加到使用子句中;

于 2013-02-02T19:53:09.240 回答
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

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

于 2013-02-02T11:50:01.767 回答
2

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

uses
  ToolsAPI;

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

您可能还会发现这个问题很有趣。

于 2013-02-02T09:17:07.520 回答