Delphi中替换组件类

15

我知道在某个地方看到过一个技巧,可以定义一个与现有VCL组件相同类名的自定义版本,比如TButtonTEdit,并采取某些措施使DFM流解器实例化您的版本而不是原始版本。 不幸的是,我现在需要能够做到这一点,但我找不到相关文档。 有人知道在哪里可以找到关于如何实现这一点的信息吗?

2个回答

24

您可以像这样在表单中覆盖 ReadState 方法:

type
  TMyForm = class(TForm)
  protected
    procedure ReadState(Reader: TReader); override;
  end;

procedure TMyForm.ReadState(Reader: TReader);
begin
  Reader.OnFindComponentClass := FindComponentClass;
  inherited;
end;

procedure TMyForm.FindComponentClass(Reader: TReader; const ClassName: string;
  var ComponentClass: TComponentClass);
begin
  if ComponentClass=TButton then begin
    ComponentClass := TMySuperDuperButton;
  end else if ComponentClass=TEdit then begin
    ComponentClass := TMyTotallyAwesomeEdit;
  end;
end;

可能有许多其他方法可以做到这一点,但这是我做的方法!

编辑:TReader.GetFieldClass(Instance: TObject; const ClassName: string)的检查表明了Mason回忆起的hack。第一行设置ClassType := Instance.ClassType。因此,我怀疑通过将pas文件中的声明从Button1: TButton更改为Button1:MyUnit.TButton会导致您创建的按钮被创建。或者也许hack是在结尾处将MyUnit添加到使用条款中,以便您的TButton版本是在范围内的那个版本。然而,所有这些听起来都不是很实际。


有没有办法将这个设置为整个应用程序中所有窗体的全局变量,而不仅仅是这一个窗体? - Mason Wheeler
4
@Mason 我的应用程序中的所有窗体都是从 TMyForm 派生的。这是我向每个人推荐的东西! - David Heffernan
1
@Mason 否则,你可以像 Andreas Hausladen 一样在运行时修补它。 - David Heffernan
@David:啊哈!是的,就是这个问题。你需要在窗体的uses子句中加入新类的单元,这样编译器才能正确设置类。但你的版本实际上更好,因为大多数涉及的窗体确实都派生自一个共同的基础窗体类。所以我会将其标记为已接受。 - Mason Wheeler

12

我猜你试图记住的是一个“中间层类”:继承一个给定名称与祖先相同但前缀为祖先单位名称的类。由于类名未更改,dfm流机制不会受到影响。只会影响重新声明该类的单元,除非将其放入一个单独的单元中并在基类之后的uses部分引用该单元。显然,您无法在中间层类中使用已发布的属性。

type
  TButton = class(stdctrls.TButton)
  protected
    procedure CreateParams(var Params: TCreateParams); override;
  end;

  TForm1 = class(TForm)
    Button1: TButton;
    [...]
  private

是的,那正是我所想的。但是David的解决方案对于我试图解决的问题更加有效。 - Mason Wheeler

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接