天道酬勤,学无止境

Delphi:如何在虚方法上调用继承的继承祖先?(Delphi: How to call inherited inherited ancestor on a virtual method?)

问题

我覆盖了一个虚方法,我想调用继承的。 但是我不想调用直系祖先,我想调用之前的那个。

TObject
   TDatabaseObject
      TADODatabaseObject <---call this guy
         TCustomer        <---skip this guy
            TVIP           <---from this guy

我尝试将self为祖先,并在其上调用该方法,但导致递归堆栈溢出:

procedure TVip.SetProperties(doc: IXMLDOMDocument);
begin
   TADODatabaseObject(Self).SetProperties(doc); //skip over TCustomer ancestor
   ...
end;

我尝试添加inherited关键字,但不能编译:

procedure TVip.SetProperties(doc: IXMLDOMDocument);
begin
   inherited TADODatabaseObject(Self).SetProperties(doc); //skip over TCustomer ancestor
   ...
end;

可能的?

回答1

你不能以常规语言的方式,因为这会破坏语言的面向对象方面。

你可以摆弄指针和聪明的演员来做到这一点,但在开始回答之前:这真的是你想要的吗?

正如其他人提到的:您的需求听起来像是一种严重的“设计气味”(类似于代码气味,但更严重。

编辑:

沿着指针摆弄的道路走下去可能会在短期内节省您的工作,从长远来看可能会花费您数周的工作时间。
这使得一些很好的阅读:上游决策,下游成本。

回答2

您可以使用获取虚拟方法的静态地址的技巧来做到这一点:

type
  TBase = class
    procedure Foo; virtual;
  end;

  TAnsestor = class(TBase)
    procedure Foo; override;
  end;

  TChild = class(TAnsestor)
    procedure Foo; override;
    procedure BaseFoo;
  end;

procedure TBase.Foo;
begin
  ShowMessage('TBase');
end;

procedure TAnsestor.Foo;
begin
  ShowMessage('TAnsestor');
end;

procedure TChild.Foo;
begin
  ShowMessage('TChild');
end;

type
  TFoo = procedure of object;

procedure TChild.BaseFoo;
var
  Proc: TFoo;

begin
  TMethod(Proc).Code := @TBase.Foo; // Static address
  TMethod(Proc).Data := Self;
  Proc();
end;

procedure TForm4.Button1Click(Sender: TObject);
var
  Obj: TChild;
  Proc: TFoo;

begin
  Obj:= TChild.Create;
  Obj.BaseFoo;
// or else
  TMethod(Proc).Code := @TBase.Foo; // Static address
  TMethod(Proc).Data := Obj;
  Proc();

  Obj.Free;
end;
回答3

我记得几年前我不得不做这样的事情来解决 VCL 层次结构的一些设计限制。

所以它似乎是这样的:

type
  TGrandParent = class(TObject)
  public
    procedure Show;virtual;
  end;

  TParent = class(TGrandParent)
  public
    procedure Show;override;
  end;

  THackParent = class(TGrandParent)
  private
    procedure CallInheritedShow;
  end;

  TMyObject = class(TParent)
  public
    procedure Show;override;
  end;


{ TGrandParent }

procedure TGrandParent.Show;
begin
  MessageDlg('I''m the grandparent', mtInformation, [mbOk], 0);
end;

{ TParent }

procedure TParent.Show;
begin
  inherited;
  MessageDlg('I''m the parent', mtInformation, [mbOk], 0);
end;

{ THackParent }

procedure THackParent.CallInheritedShow;
begin
  inherited Show;
end;

{ TVIP }

procedure TMyObject.Show;
begin
  THackParent(Self).CallInheritedShow;
end;

procedure TForm6.Button6Click(Sender: TObject);
var
  VIP: TMyObject;
begin
  VIP:=TMyObject.Create;
  try
    VIP.Show;
  finally
    VIP.Free;
  end;
end;

不是超级优雅,但仍然是一个解决方案:)

回答4

如果您真的想要这样做,那么您应该将您希望能够直接引用的继承层次结构部分提取到一个单独的受保护方法中。 这将允许您从任何地方调用它,而不会让虚方法调度打败您。

但是,正如我所评论的,您的课程设计似乎有些问题。

回答5

使用 TGrandAncestor(self).DoSomething();

TCar = class
    procedure Ride();
TBlueCar = class(TCar)
    procedure Ride();
TCar1 = class(TBlueCar)
    procedure Ride();

procedure TCar.Ride();
begin
  writeln('Riding')
end;
procedure TBlueCar.Ride();
begin
  writeln('I am blue')
  inherited Ride();
end;
procedure TCar1.Ride();
begin
  writeln('I am car1')
  TCar(self).Ride();
end;

受限制的 HTML

  • 允许的HTML标签:<a href hreflang> <em> <strong> <cite> <blockquote cite> <code> <ul type> <ol start type> <li> <dl> <dt> <dd> <h2 id> <h3 id> <h4 id> <h5 id> <h6 id>
  • 自动断行和分段。
  • 网页和电子邮件地址自动转换为链接。

相关推荐
  • 德尔福:如何隐藏祖先的构造函数?(Delphi: How to hide ancestor constructors?)
    问题 更新:用一个简单的例子来说明问题,但最初接受的答案未回答 给定以下类及其祖先: TComputer = class(TObject) public constructor Create(Teapot: string=''); end; TCellPhone = class(TComputer) public constructor Create(Cup: Integer); overload; virtual; constructor Create(Cup: Integer; Teapot: string); overload; virtual; end; 现在, TCellPhone具有3个可见的构造函数: 杯子:整数杯子:整数; 茶壶:串茶壶:字符串=” 我如何对TCellPhone进行操作,以使祖先构造函数( Teapot: string = '' )不可见,仅保留已声明的构造函数: 杯子:整数杯子:整数; 茶壶:串 注意:通常,拥有后代构造函数的简单动作会隐藏祖先: TCellPhone = class(TComputer) public constructor Create(Cup: Integer); virtual; end; 杯子:整数如果要保留祖先构造函数和后代,则将后代标记为overload : TCellPhone = class(TComputer)
  • 如何在 Delphi 中使用或解决视觉表单继承问题?(How do I use or resolve issues with visual form inheritance in Delphi?)
    问题 我一直在 Delphi 7 中从事一个项目,我希望表单从其他表单继承组件。 我能够使其正常工作,但遇到以下问题(我将发布解决方案以希望在未来帮助其他人): 在表单的 .pas 文件中,我会将表单更改为从其他表单继承,但它不会从祖先表单中获取组件。 对于某些后代表单,我在设计时打开表单时会收到以下错误消息:“创建表单时出错:未找到‘TAncestorForm’的祖先。” 我必须先手动打开祖先窗体,然后才能打开后代窗体。 回答1 首先,对于那些不知道如何直观地继承表单的人,您可以像往常一样创建祖先表单。 然后转到文件>新建>其他。 选择带有当前项目名称的选项卡,然后选择要继承的表单。 如果要从不属于当前项目的表单继承,请打开该表单,右键单击它,然后选择“添加到存储库”。 然后,您将能够转到文件 > 新建 > 其他,然后从相应的选项卡中选择该表单。 鉴于此,我遇到了一些问题,因为已经创建了一些后代表单,因此我无法遵循上述过程。 此外,我对 Delphi 创建的标准代码中的表单进行了一些更改。 我能够使用以下指南解决视觉表单继承的所有问题: 后代表单的 .pas 文件必须让表单的类继承自正确的祖先类,例如: type TMyForm = class(TAncestorForm) 后代形式的 .dfm 中的第一行必须有词inherited而不是object ,例如: inherited
  • Delphi:了解构造函数(Delphi: Understanding constructors)
    问题 我想了解 虚拟的覆写超载重新介绍 当应用于对象构造函数时。 每次我随机添加关键字直到编译器关闭-并且(在使用Delphi开发12年之后)我都希望知道自己在做什么,而不是随机尝试。 给定一个假设的对象集: TComputer = class(TObject) public constructor Create(Cup: Integer); virtual; end; TCellPhone = class(TComputer) public constructor Create(Cup: Integer; Teapot: string); virtual; end; TiPhone = class(TCellPhone) public constructor Create(Cup: Integer); override; constructor Create(Cup: Integer; Teapot: string); override; end; 我希望它们的行为方式从声明中可能很明显,但是: TComputer具有简单的构造函数,后代可以覆盖它 TCellPhone有一个备用构造函数,后代可以覆盖它 TiPhone覆盖了两个构造函数,调用了每个构造函数的继承版本 现在,该代码无法编译。 我想了解为什么它不起作用。 我也想了解重写构造函数的正确方法。 也许您永远无法覆盖构造函数
  • Delphi 接口继承:为什么我不能访问祖先接口的成员?(Delphi interface inheritance: Why can't I access ancestor interface's members?)
    问题 假设您有以下内容: //Note the original example I posted didn't reproduce the problem so //I created an clean example type IParent = interface(IInterface) ['{85A340FA-D5E5-4F37-ABDD-A75A7B3B494C}'] procedure DoSomething; end; IChild = interface(IParent) ['{15927C56-8CDA-4122-8ECB-920948027015}'] procedure DoSomethingElse; end; TGrandParent = class(TInterfacedObject) end; TParent = class(TGrandParent) end; TChild = class(TParent, IChild) private FChildDelegate: IChild; public property ChildDelegate:IChild read FChildDelegate implements IChild; end; TChildDelegate = class(TInterfacedObject, IChild)
  • 如何在Delphi中实现多重继承?(How to implement multiple inheritance in delphi?)
    问题 我正在完全重写旧库,并且不确定如何处理这种情况(为便于理解,所有这些都以自行车类比为标准): 我有以下课程: TBike自行车本身 TBikeWheel自行车车轮之一 TBikeWheelFront和TBikeWheelBack都继承自TBikeWheel ,然后在其之上实现所需的特定内容 这非常简单,但是现在我决定创建多种类型的自行车,每个自行车都有自己的车轮-它们的作用与普通的前/后轮相同,并且具有该自行车的特定功能。 TBikeXYZ继承自TBike TBikeWheelXYZ继承自TBikeWheel 这是我的问题: TBikeWheelFrontXYZ应该继承自TBikeWheelXYZ (以获取XYZ车轮的特定方法),但它也应该继承自TBikeWheelFront (以获取前轮的特定方法)。 我的问题是,我该如何以一种不这样的方式实现该目标: 感觉像个黑客强迫我多次重写相同的代码 回答1 Delphi不支持多重继承。 但是类可以支持/实现多个接口,并且您可以委派接口的实现,因此可以模拟多个继承。 回答2 使用界面。 像这样(根据您的描述,我的头顶……) type IBikeWheel = interface ... end; IXYZ = interface ... end; IFrontWheel = interface(IBikeWheel) ... end
  • 如何在 Delphi 的 TFrame 上模拟 OnDestroy 事件?(How to simulate an OnDestroy event on a TFrame in Delphi?)
    问题 如何在 Delphi 中为TFrame模拟OnDestroy事件? 我 nievely 在我的框架中添加了一个constructor和destructor ,认为这就是TForm所做的: TframeEditCustomer = class(TFrame) ... public constructor Create(AOwner: TComponent); override; destructor Destroy; override; ... end; constructor TframeEditCustomer.Create(AOwner: TComponent) begin inherited Create(AOwner); //allocate stuff end; destructor TframeEditCustomer.Destroy; begin //cleanup stuff inherited Destroy; end; 问题在于,当我的析构函数运行时,框架上的控件已被销毁并且不再有效。 原因在于包含表单的析构函数,它用于触发OnDestroy事件: destructor TCustomForm.Destroy; begin ... if OldCreateOrder then DoDestroy; //-->fires Form's OnDestroy
  • 我需要在派生类中的构造函数声明之后放置重载或覆盖词吗?(Need I to put overload or override words after the constructor declaration in derived class?)
    问题 我有一个类层次结构,这个: type TMatrix = class protected //... public constructor Create(Rows, Cols: Byte); //... type TMinMatrix = class(TMatrix) private procedure Allocate; procedure DeAllocate; public constructor Create(Rows, Cols: Byte); constructor CreateCopy(var that: TMinMatrix); destructor Destroy; end; 如您所见,派生类和基类构造函数都具有相同的参数列表。 我从派生的一个显式调用基类构造函数: constructor TMinMatrix.Create(Rows, Cols: Byte); begin inherited; //... end; Delphi中是否有必要显式调用基类构造函数? 可能我需要放超载或覆盖来清除我打算做什么? 我知道如何在 C++ 中做到这一点——只有当你想向它传递一些参数时,你才需要显式调用基类构造函数——但我在 Delphi 编程方面没有太多经验。 回答1 据我所知,这里有两个不同的问题: 确保子类的构造函数调用基类的构造函数 您必须显式调用基类的构造函数
  • 如何在线程的执行中使用字典/字符串列表 - delphi(How can I use a Dictionary/StringList inside Execute of a Thread - delphi)
    问题 我有一个线程类 TValidateInvoiceThread: type TValidateInvoiceThread = class(TThread) private FData: TValidationData; FInvoice: TInvoice; // Do NOT free FPreProcessing: Boolean; procedure ValidateInvoice; protected procedure Execute; override; public constructor Create(const objData: TValidationData; const bPreProcessing: Boolean); destructor Destroy; override; end; constructor TValidateInvoiceThread.Create(const objData: TValidationData; const bPreProcessing: Boolean); var objValidatorCache: TValidationCache; begin inherited Create(False); FData := objData; objValidatorCache := FData.Caches.Items[
  • 在delphi中替换组件类(Replacing a component class in delphi)
    问题 我知道我看到了一个例子,该例子使用相同的类名定义了现有VCL组件(如TButton或TEdit)的自定义版本,并做了一些使之成为现实的事,以便DFM流化器将实例化您的版本,而不是实例化该版本。原本的。 不幸的是,我处于需要做到这一点而找不到书面记录的情况下。 有人知道在哪里可以找到有关如何完成此操作的信息吗? 回答1 在您的表单中,您可以像这样重写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
  • 泛型类的类助手?(Class Helper for generic class?)
    问题 我正在使用 Delphi 2009。是否可以为泛型类(即 TQueue )编写类助手。 显而易见的 TQueueHelper <T> = class helper of TQueue <T> ... end; 不起作用,也不起作用 TQueueHelper = class helper of TQueue ... end; 回答1 正如 Delphi 帮助中所记录的那样,类助手不是为通用用途而设计的,因此它们被错误地认为具有许多限制甚至错误。 然而,有一种看法——在我看来是不正确和危险的——认为这些是通用“工具包”中的合法工具。 我已经在博客中介绍了为什么这是错误的,随后介绍了如何通过遵循对社会负责的编码模式来减轻危险(尽管这也不是防弹的)。 通过对从您尝试扩展的类派生的“伪”类使用硬转换,您可以实现类助手的大部分效果,而没有任何这些错误或限制或(最重要的)风险。 即而不是: TFooHelper = class helper for TFoo procedure MyHelperMethod; end; 用 TFooHelper = class(TFoo) procedure MyHelperMethod; end; 就像使用“正式”助手一样,您永远不会实例化这个TFooHelper类,您仅使用它来改变TFoo类,除非在这种情况下您必须明确。 在您的代码中,当您需要使用
  • Delphi:确定泛型的实际类型?(Delphi: determine actual type of a generic?)
    问题 有什么方法可以确定作为参数传递给方法的变量的类型吗? 考虑一下类: TSomeClass = class procedure AddToList<T: TDataType; U: TListClass<T>>(Element: T; List: U); end; 与方法实现 procedure TSomeClass.AddToList<T, U>(Element: T; List: U); begin if Element is TInt then List.AddElement(TInt.Create(XXX)) else if Element is TString then List.AddElement(TString.Create(YYY)); end; 其中TInt.Create()和TString.Create()具有不同的参数集,但是它们都继承自TDataType。 现在,我知道的is -运算符不能这样使用,但有,做我问这里有什么法律的选择吗? 回答1 这里不能使用is运算符是一个已知问题,但是有一个非常简单的解决方法。 if TObject(Element) is TInt then List.AddElement(TInt.Create(XXX)) 另外,由于泛型的类型是该类的一部分,并且在编译时是已知的,因此最好重组代码。 制作两个不同的泛型类
  • Delphi 中的记录(Records in Delphi)
    问题 关于Delphi中记录的一些问题: 由于记录几乎就像类,为什么不只使用类而不使用记录呢? 理论上,当一条记录由一个变量声明时,它就会为一条记录分配内存; 但是,之后如何释放内存? 我可以理解指向列表对象的记录指针的效用,但是对于泛型容器( TList<T> ),是否还需要使用指针? 如果没有,如何将每条记录删除/释放到通用容器中? 如果我想将特定记录删除到通用容器中,该怎么做? 回答1 对于 1 和 2:记录是值类型,而类是引用类型。 它们在堆栈上分配,或直接在包含它们的任何更大变量的内存空间中分配,而不是通过指针,并在超出范围时由编译器自动清除。 至于你的第三个问题,一个TList<TMyRecord>内部声明了一个array of TMyRecord作为存储空间。 当列表被销毁时,其中的所有记录都会被清除。 如果要删除某个特定的,可以使用Delete方法按索引删除,或者使用Remove方法查找并删除。 但请注意,由于它是一种值类型,因此您所做的一切都将复制记录,而不是复制对它的引用。 回答2 记录和类之间有很多差异; 并且没有“记录指针” <> “类”。 各有优缺点; 关于软件开发的重要事情之一是了解这些,以便您可以更轻松地选择最适合给定情况的方法。 这个问题是基于一个错误的前提。 记录不像类,就像整数也不像双精度一样。 类必须始终动态实例化,这是一种可能性
  • 为什么Delphi记录不能有继承?(Why can't Delphi records have inheritance?)
    问题 我一直想知道的事情:为什么 Delphi 记录不能具有继承性(以及所有其他重要的 OOP 特性)? 这本质上会使记录成为类的堆栈分配版本,就像 C++ 类一样,并且会使“对象”(注意:不是实例)过时。 我看不出有什么问题。 这也是实现记录前向声明的好机会(我仍然对为什么它仍然缺失感到困惑)。 你觉得这有什么问题吗? 回答1 与这个问题相关的继承有两种:接口继承和实现继承。 接口继承通常意味着多态性。 这意味着如果 B 派生自 A,那么类型 B 的值可以存储在类型 A 的位置。由于切片,这对于值类型(如记录)而不是引用类型是有问题的。 如果 B 大于 A,则将其存储在类型 A 的位置将截断该值 - B 在其定义中添加的超出 A 的字段的任何字段都将丢失。 从这个角度来看,实现继承问题较少。 如果 Delphi 有记录继承,但只有实现,而不是接口,事情就不会太糟糕。 唯一的问题是,简单地将 A 类型的值设置为 B 类型的字段可以完成您想要实现继承的大部分工作。 另一个问题是虚方法。 虚拟方法分派需要某种 per-value 标记来指示值的运行时类型,以便可以发现正确的重写方法。 但是记录没有任何地方可以存储这种类型:记录的字段是它拥有的所有字段。 对象(旧的 Turbo Pascal 类型)可以有虚方法,因为它们有一个 VMT:层次结构中第一个定义虚方法的对象隐式地将一个 VMT
  • 在 TWinControl 类上添加属性(Add a property on TWinControl Class)
    问题 我想在 TWinControl 中添加一个已发布的属性。 有没有办法在不需要重新编译基本源代码的情况下做到这一点? 如果没有,有什么方法可以重新编译基本源代码而不会有太多麻烦? 忠告... 编辑新想法的原因 好吧,我想做什么我正在尝试覆盖 System.pas 中的 _GetMem 以获取从 TWinControl 继承的类。 为什么 ? 因为我会为对象分配一些额外的空间,足够一个整数。 为什么是整数? 因为这样我可以添加任何指向对象的指针。 因此,在 TWinControl 的帮助器类上,我可以创建一个 Get 一个 Set 函数来访问这个内存空间。 很好不是吗? 这该怎么做 ? 覆盖 GetMem 过程我可以使用在 FastCode 上使用的相同策略,为新过程创建一个跳线。 我现在需要的是了解这个内存分配如何工作 InstanceSize 来覆盖它。 我正在研究 Delphi 是如何做到这一点的……为了在 DFM 上添加这个,我会以同样的方式做,我会为文件管理器创建一个跳线。 有人有一些想法在对象中添加新空间吗? 我需要覆盖什么方法? 跳投我知道怎么做。 再一次。 编辑 = 进化 我想我做了内存注入。 我需要做更多的测试。 我刚刚做了,我现在不关心优化,如果有人想测试它,代码在这里。 只需将该单元添加为项目的第一个单元即可。 unit uMemInjection
  • Delphi:如何使 ENTER 键在 TFrame 中用作 TAB 键(Delphi: How to make ENTER key works as TAB key in TFrame)
    问题 我有一个框架和一些控件(编辑、按钮等)。 如何拦截在框架控件上任意位置按下 ENTER 键并将其转换为 TAB 键(考虑到 SHIFT 状态)? 回答1 下面是一些示例代码,它们将处理框架上的消息,以便在按下Enter时能够导航到下一个控件。 请注意,此示例不会将Enter键修改为Tab键。 相反,它选择下一个控件并阻止进一步处理按键消息。 另请注意,代码可能需要进一步调整。 一个是,如果任何控件实际上需要处理Enter键,例如TMemo ,您需要添加一个例外。 其次,导航被包裹在框架中,即在最后一个框架控件之后,第一个框架控件被聚焦——不是窗体上的控件,也不是框架上的控件。 对于这些,您可能希望为消息返回添加条件,如果您希望在某些条件下进行默认处理,只需调用继承而不做任何其他事情。 type TFrame2 = class(TFrame) ... protected procedure CMChildKey(var Message: TCMChildKey); message CM_CHILDKEY; end; .. procedure TFrame2.CMChildKey(var Message: TCMChildKey); begin if Message.CharCode = VK_RETURN then begin SelectNext(Screen
  • 如何检查一个类是否实现了一个接口,并尊重超集?(How to check if a class implements an interface, with respecting supersets?)
    问题 我正在学习COM和接口,并具有以下实验代码: type IA = interface(IInterface) ['{C9C5C992-3F67-48C5-B215-7DCE6A61F0E8}'] end; IB = interface(IA) ['{F1799437-AD12-471B-8716-F1D93D1692FC}'] end; IC = interface(IB) ['{01780E8C-C47D-468E-8E42-4BFF3F495D51}'] end; TBO = class(TInterfacedObject, IB) end; procedure TForm1.FormCreate(Sender: TObject); var x: TBO; a: IInterface; begin x := TBO.Create; IInterface(x)._AddRef; if Assigned(TBO.GetInterfaceEntry(IA)) then memo1.lines.add('GetInterfaceEntry IA: OK'); // Why not? if Assigned(TBO.GetInterfaceEntry(IB)) then memo1.lines.add('GetInterfaceEntry IB: OK'); if Assigned
  • 如何在 Delphi 中显示 Vista 风格的气球提示?(How to show Vista style balloon hints in Delphi?)
    问题 在输入验证中,我使用的是气球提示而不是消息框。 我的问题是在 Vista 上,它们具有带有圆角的旧 XP 样式,而不是较新的更像矩形的外观。 我尝试使用 CreateWindowEx 和tooltips_class32创建它们或使用 SendMessageW 和EM_SHOWBALLOONTIP显示编辑的关联气球EM_SHOWBALLOONTIP ,结果是一样的。 在 Visual Studio 和 C# 中做同样的事情会产生一个 Vista 风格的气球提示。 您可以看到我需要的气球提示示例,当您在密码编辑中切换 Caps Lock 时,就像 Windows 登录中的那个。 回答1 如果您使用的是 Delphi 2009,那么添加气球提示相当简单,尽管文档很差。 (惊喜,惊喜) 在你的表单上放一个 TballoonHint 如果需要,删除 TImageList 以包含图标。 将 TIMageList 链接到 TBalloonHint 将表单的 CustomHint 属性设置为 TBalloonHint 确保 ShowHint 和 ParentCustomHint 为您的控件设置为 true。 下一点非常不明显: 将控件的“Hint”属性格式化为“Title|Hint|ImageIndex” 你完成了。 这看起来不像 100% vista,可能是由于字体选择。 但它非常接近。
  • 以自定义构造函数作为主窗体的 Delphi 窗体?(Delphi Form with custom constructor as the mainform?)
    问题 我想要一个从具有自定义构造函数的 BaseForm 派生的 MainForm。 由于这是 Mainform,它是通过调用 *.dpr 文件中的Application.CreateForm(TMyMainForm, MyMainForm)创建的。 但是,在表单创建期间不会调用我的自定义构造函数。 显然,它工作正常,如果我调用MyMainForm := TMyMainForm.Create(AOwner) 。 我可以不使用带有自定义构造函数的表单作为主表单吗? TBaseForm = class(TForm) constructor Create(AOwner:TComponent; AName:string);reintroduce; end; TMyMainForm = class(TBaseForm) constructor Create(AOwner:TComponent);reintroduce; end; constructor TBaseForm.Create(AOwner:TComponent); begin; inherited Create(AOwner); end; constructor TMyMainForm.Create(AOwner:TComponent); begin; inherited Create(AOwner, 'Custom
  • 如何提高delphi应用程序的启动速度?(How to increase the startup speed of the delphi app?)
    问题 如何提高Delphi应用程序的启动速度(或减少启动时间)? 除了特定于应用程序之外,是否有始终有效的标准技巧? 注意:我不是在谈论快速算法或类似算法。 就速度而言,仅在启动时性能有所提高。 回答1 尝试在主窗体的OnCreate事件中尽可能少地做。 而是将一些初始化移至其他方法,并在将表单显示给用户后进行初始化。 应用程序正忙于鼠标光标的指示符很长一段路要走。 完成的实验表明,如果您使用完全相同的应用程序,并只是向其添加启动通知,则用户实际上会认为该应用程序启动速度更快! 除此之外,您还可以执行常规操作,例如排除调试信息并在编译器中启用优化。 最重要的是,不要自动创建所有表单。 根据需要动态创建它们。 回答2 在项目选项中,不要预先自动创建所有表单。 根据需要创建并释放它们。 回答3 好吧,正如Argalatyr建议的那样,我将我的评论更改为单独的答案: 作为对“不要自动创建表单”答案的扩展(它本身将非常有效),我建议延迟与数据库,Internet,COM服务器和任何外围设备的连接打开,直到您首先需要它为止。 回答4 在显示表单之前发生了三件事: 所有单元中的所有“初始化”块均按“先见”顺序执行。 将创建所有自动创建的表单(从DFM文件加载并调用其OnCreate处理程序) 显示主窗体(调用OnShow和OnActivate)。 正如其他人指出的那样,您应该仅自动创建少量表单
  • Delphi中为其他Windows Message访问和继承Windows Message(Accessing and inheriting Windows Message for other Windows Message in Delphi)
    问题 我正在使用 WMSysCommand 消息来修改标题栏按钮(最大化/最小化)行为,并且最近更新需要使用 WMNCHitTest,但由于代码冗长,我不想在乘法过程中拆分这两个相关消息。 我可以从其他消息访问私人声明(消息)吗? 如果可以的话 - 怎么做? procedure TForm1.WMNCHitTest(var Msg: TWMNCHitTest) ; begin SendMessage(Handle, HTCAPTION, WM_NCHitTest, 0); // or other wParam or lParam ???? end; procedure TForm1.WMSysCommand; begin if (Msg.CmdType = SC_MAXIMIZE or 61488) or (Msg.Result = htCaption or 2) then // if command is Maximize or reciever message of Caption Bar click begin if CheckWin32Version(6, 0) then Constraints.MaxHeight := 507 else Constraints.MaxHeight := 499; Constraints.MaxWidth := 0; end else if