Delphi 未声明的标识符:“OnClick”

Delphi 未声明的标识符:“OnClick”,delphi,Delphi,为什么会出现此错误消息:未声明的标识符:“OnClick” 我使用的是Delphi 7,以下是我的完整代码: procedure TForm1.Button1Click(Sender: TObject); var SavedOnClick : TNotifyEvent; begin SavedOnClick := TControl(Sender).OnClick; try // Code which takes some time finally TControl

为什么会出现此错误消息:未声明的标识符:“OnClick”

我使用的是Delphi 7,以下是我的完整代码:

procedure TForm1.Button1Click(Sender: TObject);
var
  SavedOnClick : TNotifyEvent;
begin
  SavedOnClick := TControl(Sender).OnClick;
  try
    // Code which takes some time
  finally
    TControl(Sender).OnClick := SavedOnClick;
  end;
end;

铸造时,使用TButton而不是TControl。TControl的OnClick属性受保护。

强制转换时,请使用TButton而不是TControl。TControl的OnClick属性受保护。

如果查看TControl,OnClick属性被定义为受保护。IE除了子类之外,它不可见。有两种简单的方法,第一种是使用TButtonSender.OnClick,第二种是创建一个hack类,您可以使用它来访问属性:

type
  TControlOnClickHack = class(TControl)
    published
    property OnClick;
  end;
然后使用TControlOnClickHackSender.OnClick


警告,在您决定使用后一种方法之前,请确保您的发件人具有onClick事件。TypInfo提供了一个名为IsPublishedProp的函数,在您尝试取消设置/设置属性之前最好使用该函数。

如果您查看TControl,OnClick属性被定义为受保护。IE除了子类之外,它不可见。有两种简单的方法,第一种是使用TButtonSender.OnClick,第二种是创建一个hack类,您可以使用它来访问属性:

type
  TControlOnClickHack = class(TControl)
    published
    property OnClick;
  end;
然后使用TControlOnClickHackSender.OnClick


警告,在您决定使用后一种方法之前,请确保您的发件人具有onClick事件。TypInfo提供了一个名为IsPublishedProp的函数,在您尝试取消设置/设置属性之前,最好使用该函数。

声明一个类,该类将在同一单元中扩展TControl,就像在TControl中保护单击时希望访问受保护成员的代码一样

因为新类在单元中,所以我们可以直接访问该单元中其他类的受保护成员。它不需要,我想说的是,不需要在界面中,因为它严格地说是您单元的实现细节:

  unit ... ;

interface

  :

implementation

  :

type
  TControlHelper = class(TControl);


// Now we can type-cast to the "helper" class to gain access
//  to the protected members of the ancestor:

procedure TForm1.Button1Click(Sender: TObject);
var
  SavedOnClick : TNotifyEvent;
begin
  if Sender is TControl then
    SavedOnClick := TControlHelper(Sender).OnClick;

  try
    // Code which takes some time

  finally
    if (Sender is TControl) then
      TControlHelper(Sender) := SavedOnClick;
  end;
end;
请注意,在检查发送者类型时,我们会检查所需祖先类的实例,因为它永远不会是帮助器类本身的实例。作为TControl的任何对象都可以作为TControlHelper安全地访问,而不管它可能是哪个实际派生类的实例

出于这个原因,我不同意这是一个黑客行为,因为它有我认为不应该应用的负面含义——这里没有任何东西是不安全的或容易被破坏的。这是一种利用语言特性的技术,仅此而已

注意:我称这个类为TControlHelper,但它不是Delphi2007及更高版本中定义和实现的类帮助器,尽管它在您可以实现的方面有大约90%的共同点,而且事实上imho比那些真正的帮助器更安全

此外,您还可以利用absolute关键字清理类型转换,只要您保持类型检查到位,这是非常好的,就像硬转换一样安全,功能相同,并且更易于阅读imho:

procedure TForm1.Button1Click(Sender: TObject);
var
  control: TControlHelper absolute Sender;
  SavedOnClick : TNotifyEvent;
begin
  if Sender is TControl then
    SavedOnClick := control.OnClick;

  try
    // Code which takes some time
  finally
    if (Sender is TControl) then
      control.OnClick := SavedOnClick;
  end;
end;

声明一个类,该类将在同一单元中扩展TControl,因为在TControl中保护单击时,希望访问受保护成员的代码受保护

因为新类在单元中,所以我们可以直接访问该单元中其他类的受保护成员。它不需要,我想说的是,不需要在界面中,因为它严格地说是您单元的实现细节:

  unit ... ;

interface

  :

implementation

  :

type
  TControlHelper = class(TControl);


// Now we can type-cast to the "helper" class to gain access
//  to the protected members of the ancestor:

procedure TForm1.Button1Click(Sender: TObject);
var
  SavedOnClick : TNotifyEvent;
begin
  if Sender is TControl then
    SavedOnClick := TControlHelper(Sender).OnClick;

  try
    // Code which takes some time

  finally
    if (Sender is TControl) then
      TControlHelper(Sender) := SavedOnClick;
  end;
end;
请注意,在检查发送者类型时,我们会检查所需祖先类的实例,因为它永远不会是帮助器类本身的实例。作为TControl的任何对象都可以作为TControlHelper安全地访问,而不管它可能是哪个实际派生类的实例

出于这个原因,我不同意这是一个黑客行为,因为它有我认为不应该应用的负面含义——这里没有任何东西是不安全的或容易被破坏的。这是一种利用语言特性的技术,仅此而已

注意:我称这个类为TControlHelper,但它不是Delphi2007及更高版本中定义和实现的类帮助器,尽管它在您可以实现的方面有大约90%的共同点,而且事实上imho比那些真正的帮助器更安全

此外,您还可以利用absolute关键字清理类型转换,只要您保持类型检查到位,这是非常好的,就像硬转换一样安全,功能相同,并且更易于阅读imho:

procedure TForm1.Button1Click(Sender: TObject);
var
  control: TControlHelper absolute Sender;
  SavedOnClick : TNotifyEvent;
begin
  if Sender is TControl then
    SavedOnClick := control.OnClick;

  try
    // Code which takes some time
  finally
    if (Sender is TControl) then
      control.OnClick := SavedOnClick;
  end;
end;

您确定实际的错误消息不是[DCC error]。。。E2362无法访问受保护的符号t控件。OnClick?这是一种非常糟糕的方法。onclick事件处理程序更改为删除处理程序,然后替换它,而不仅仅是在忙时禁用操作或控件,或者在忙时从Click方法返回?噢,请仅禁用该操作!!我现在无法访问Delphi。我知道有很多方法可以禁用某个操作,但是有没有方法可以阻止TControl执行事件?如果禁用某个操作,则

与之关联的控件也将被禁用。您确定实际的错误消息不是[DCC error]。。。E2362无法访问受保护的符号t控件。OnClick?这是一种非常糟糕的方法。onclick事件处理程序更改为删除处理程序,然后替换它,而不仅仅是在忙时禁用操作或控件,或者在忙时从Click方法返回?噢,请仅禁用该操作!!我现在无法访问Delphi。我知道有很多方法可以禁用某个操作,但有没有方法可以阻止TControl执行事件?如果禁用某个操作,与之相关的控件也将被禁用。无需破解任何东西,您知道该控件是一个按钮,而且由于TButton属性显然已发布,因为它在对象检查器中可见。您应该将发送者强制转换为TButton。是的,但只是为了防止他想将其与按钮以外的控件一起使用。我见过很多人喜欢直接从按下Enter键时的OnKeyDown事件调用事件处理程序,而不是调用按钮本身的.Click过程。-1,无需破解控件,无论它是什么类型。如果您能够在设计时或运行时分配它的OnClick,那么它的OnClick属性必须是published或public,您应该强制转换为控件的实际类型。请给出一个类型的示例,您实际上需要强制转换到TControlOnClickHack,因为强制转换到实际类型不会公开OnClick。@Cosmin-为什么您认为事件总是由TButton生成?仅仅因为默认事件处理程序是由IDE从一个关联的按钮生成的,您根本无法知道这个处理程序可能不会从其他控制类调用。事实上,我认为OP正在向TControl(而不是TButton)施压这一事实强烈暗示了这种可能性。使用helper not hack类可以避免使用RTTI来发现OnClick事件的存在。无需对任何内容进行攻击,您知道控件是一个按钮,并且作为TButton属性显然已发布,因为它在Object Inspector中可见。您应该将发送者强制转换为TButton。是的,但只是为了防止他想将其与按钮以外的控件一起使用。我见过很多人喜欢直接从按下Enter键时的OnKeyDown事件调用事件处理程序,而不是调用按钮本身的.Click过程。-1,无需破解控件,无论它是什么类型。如果您能够在设计时或运行时分配它的OnClick,那么它的OnClick属性必须是published或public,您应该强制转换为控件的实际类型。请给出一个类型的示例,您实际上需要强制转换到TControlOnClickHack,因为强制转换到实际类型不会公开OnClick。@Cosmin-为什么您认为事件总是由TButton生成?仅仅因为默认事件处理程序是由IDE从一个关联的按钮生成的,您根本无法知道这个处理程序可能不会从其他控制类调用。事实上,我认为OP正在向TControl(而不是TButton)施压这一事实强烈暗示了这种可能性。使用helper not hack类可以避免使用RTTI来发现OnClick事件的存在。-1出于同样的原因,我否决了jdarling的建议:当您可以简单地强制转换到TButton时,不需要进行如此复杂的hack。而你的黑客甚至比JDLIN更精细,你使用的是绝对的关键字,在这里,一个普通的硬演员会做的。你很简单地不应该根据你自己的规则在你的简介中被否决:我只考虑错误的下落问题。OOPS:我的答案和jdarlings的答案都没有错,只是它们不是你应该怎么做的——你个人更喜欢直接将类型转换到一个假定的类;一个真正的黑客。但是我们没有机会否决你的方法,因为你自己没有费心把它作为一个答案,而是更喜欢批评别人,不公平地批评。糟糕的表现。你真的相信OP已经将Button1Click链接到了标签的OnClick处理程序,并且现在正在考虑在执行代码所需的时间内将其设置为nil的方法吗?如果你想去那里,如果OP实际分配的按钮1点击TTimer的OnTimer事件会怎么样?顺便说一下,您在这里实现的是对受保护的黑客的不必要的复杂理解。不需要绝对关键字,也不需要控制局部变量。你可以简单地使用Sender-to-TControlHelper的硬模式。我认为这并不重要——我当然不相信OP正在编写我的代码,所以我选择的回答方式似乎适合OP的代码,而不是我自己的代码。如果你看一下,你会发现我的答案中包含了这两种方法——你在跳到第二步之前完整地阅读了吗
下一票按钮?当然,这是没有必要的,但有些人可能会觉得它更可取,因为它是一种更干净、更清晰、功能等效的方法。您是否总是使用self限定对成员变量的引用?若否,原因为何?离开自我是不必要的。结束。-1出于同样的原因,我否决了jdarling的:当你可以简单地向TButton施压时,没有必要进行如此复杂的破解。而你的黑客甚至比JDLIN更精细,你使用的是绝对的关键字,在这里,一个普通的硬演员会做的。你很简单地不应该根据你自己的规则在你的简介中被否决:我只考虑错误的下落问题。OOPS:我的答案和jdarlings的答案都没有错,只是它们不是你应该怎么做的——你个人更喜欢直接将类型转换到一个假定的类;一个真正的黑客。但是我们没有机会否决你的方法,因为你自己没有费心把它作为一个答案,而是更喜欢批评别人,不公平地批评。糟糕的表现。你真的相信OP已经将Button1Click链接到了标签的OnClick处理程序,并且现在正在考虑在执行代码所需的时间内将其设置为nil的方法吗?如果你想去那里,如果OP实际分配的按钮1点击TTimer的OnTimer事件会怎么样?顺便说一下,您在这里实现的是对受保护的黑客的不必要的复杂理解。不需要绝对关键字,也不需要控制局部变量。你可以简单地使用Sender-to-TControlHelper的硬模式。我认为这并不重要——我当然不相信OP正在编写我的代码,所以我选择的回答方式似乎适合OP的代码,而不是我自己的代码。如果你看一下,你会发现我的答案中包含了这两种方法——你在跳到下一票按钮之前读了全文吗?当然,这是没有必要的,但有些人可能会觉得它更可取,因为它是一种更干净、更清晰、功能等效的方法。您是否总是使用self限定对成员变量的引用?若否,原因为何?离开自我是不必要的。结束。@Wim-在阅读本页的讨论时,您似乎丢失了问题。Andreas正在回答为什么会出现此错误的问题msg:Undeclared identifier:'OnClick',答案肯定不是因为您使用的是'TControl'而不是'Button1'。Sertac,您缺少的是事件名为TForm1.Button1Click,这表明它有一个名为Button1的控件。因此,请使用Button1对象或其重命名为的任何对象,而不是强制转换…@Wim-Q:为什么我在强制转换时会出现此错误?-A:不要投!。好的@Wim-在阅读本页的讨论时,您似乎丢失了问题。Andreas正在回答为什么会出现此错误的问题msg:Undeclared identifier:'OnClick',答案肯定不是因为您使用的是'TControl'而不是'Button1'。Sertac,您缺少的是事件名为TForm1.Button1Click,这表明它有一个名为Button1的控件。因此,请使用Button1对象或其重命名为的任何对象,而不是强制转换…@Wim-Q:为什么我在强制转换时会出现此错误?-A:不要投!。好的!