开发者

Undeclared identifier: 'OnClick'

开发者 https://www.devze.com 2023-03-23 21:16 出处:网络
Why do I get this error msg: Undec开发者_开发知识库lared identifier: \'OnClick\' I\'m using Delphi 7 and here\'s my complete code:

Why do I get this error msg: Undec开发者_开发知识库lared identifier: 'OnClick'

I'm using Delphi 7 and here's my complete code:

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;


When casting, use TButton instead of TControl. The OnClick property of the TControl is protected.


If you look at TControl the OnClick property is defined as protected. IE it is not visible except to descendant classes. There are two simple ways around this, first would be to use TButton(Sender).OnClick the second would be to create a hack class that you can use to get to the property:

type
  TControlOnClickHack = class(TControl)
    published
    property OnClick;
  end;

Then use TControlOnClickHack(Sender).OnClick

Warning, make sure your senders have an onClick event before you decide to use the later idea. TypInfo supplies a function called IsPublishedProp that would be a good idea to use before you attempt to unset/set the property.


Declare a class that extends TControl in the same unit as the code that wishes to access the protected members (OnClick is protected in TControl).

Since the new class is in the unit, we have direct access to it's protected members from other classes in that same unit. it doesn't (and I would say "shouldn't") need to be in the interface as it is strictly an implementation detail of your unit:

  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;

Notice that when checking the type of Sender we check for an instance of the desired ancestor class since it will not ever be an instance of our helper class itself. Any object that is a TControl can be safely accessed as a TControlHelper, regardless of what actual derived class it may be an instance of.

For this reason I disagree that this is a "hack", as that has negative connotations that I don't think should apply - nothing here is unsafe or liable to break. It is a technique that takes advantage of language features, nothing more.

NOTE: I called this class TControlHelper but it is NOT a "class helper" as defined and implemented in Delphi 2007 (?) and later, although it has about 90% in common in terms of what you can achieve and in fact imho is safer than those "real" helpers.

Also you can clean up the typecasting by exploiting the absolute keyword, as long as you keep the type checking in place this is perfectly (well, just as safe as hard casting), functionally identical and much cleaner to read 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;
0

精彩评论

暂无评论...
验证码 换一张
取 消

关注公众号