delphi 基础原理--什么是事件/自定义事件
2013-07-01 00:00
621 查看
Events are special properties linked to code that get executed whenever a particular action occurs. This article discusses how events are generated and how you can define your own event properties for your custom Delphi components.
This article is excerpted from
Delphi 6 Developer's Guide, by Xavier Pacheco and Steve Teixeira (Sams, 2001, ISBN 0-672-32115-7).
Where Do Events Come From?
The general definition of an event is basically any type of occurrence that might result from user interaction, the system, or from code logic. The event is linked to some code that responds to that occurrence. The linkage of the event to code that responds to an event is called an event propertyand is provided in the form of a method pointer. The method to which an event property points is called an event handler.For example, when the user clicks the mouse button, a WM_MOUSEDOWN message is sent to the Win32 system. Win32 passes that message to the control for which the message was intended. This control can then respond to the message. The control can respond to this event by first checking to see whether there is any code to execute. It does this by checking to see whether the event property points to any code. If so, it executes that code, or rather, the event handler.
The OnClick event is just one of the standard event properties defined by Delphi. OnClick and other event properties each have a corresponding event-dispatching method. This method is typically a protected method of the component to which it belongs. This method performs the logic to determine whether the event property refers to any code provided by the user of the component. For the OnClick property, this would be the Click() method. Both the OnClick property and theClick() method are defined by TControl as follows:
TControl = class(TComponent) private FOnClick: TNotifyEvent; protected procedure Click; dynamic; property OnClick: TNotifyEvent read FOnClick write FOnClick; end;Here is the TControl.Click() method:
procedure TControl.Click; begin if Assigned(FOnClick) then FOnClick(Self); end;One bit of essential information that you must understand is that event properties are nothing more than method pointers. Notice that the FOnClick property is defined to be a TNotifyEvent.TNotifyEvent is defined as follows:
TNotifyEvent = procedure(Sender: TObject) of object;This says that TNotifyEvent is a procedure that takes one parameter, Sender, which is of the typeTObject. The directive, of object, is what makes this procedure become a method. This means that an additional implicit parameter that you don't see in the parameter list also gets passed to this procedure. This is the Self parameter that refers to the object to which this method belongs. When the Click() method of a component is called, it checks to see if FOnClick actually points to a method, and if so, calls that method.
As a component writer, you write all the code that defines your event, your event property, and your dispatching methods. The component user will provide the event handler when using your component. Your event-dispatching method will check to see whether the user has assigned any code to your event property and then execute it when code exists.
Event handlers are assigned to event properties either at runtime or at design time. In the following section, we show you how to create your own events, event properties, and dispatching methods.
Defining Event Properties
Before you define an event property, you need to determine whether you need a special event type. It helps to be familiar with the common event properties that exist in the Delphi VCL. Most of the time, you'll be able to have your component descend from one of the existing components and just use its event properties, or you might have to surface a protected event property. If you determine that none of the existing events meets your need, you can define your own.As an example, consider the following scenario. Suppose you want a component containing an event that gets called every half minute based on the system clock. That is, it gets invoked on the minute and on the half minute. Well, you can certainly use a TTimer component to check the system time and then perform some action whenever the time is at the minute or half minute. However, you might want to incorporate this code into your own component and then make that component available to your users so that all they have to do is add code to your OnHalfMinuteevent.
The TddgHalfMinute component shown in Listing 1 illustrates how you would design such a component. More importantly, it shows how you would go about creating your own event type.
Listing 1—TddgHalfMinute—Event Creation
unit halfmin; interface uses Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs, ExtCtrls; type { Define a procedure for the event handler. The event property will be of this procedure type. This type will take two parameters, the object that invoked the event and a TDateTime value to represent the time that the event occurred. For our component this will be every half-minute. } TTimeEvent = procedure(Sender: TObject; TheTime: TDateTime) of object; TddgHalfMinute = class(TComponent) private FTimer: TTimer; { Define a storage field to point to the user's event handler. The user's event handler must be of the procedural type TTimeEvent. } FOnHalfMinute: TTimeEvent; FOldSecond, FSecond: Word; // Variables used in the code { Define a procedure, FTimerTimer that will be assigned to FTimer.OnClick. This procedure must be of the type TNotifyEvent which is the type of TTimer.OnClick. } procedure FTimerTimer(Sender: TObject); protected { Define the dispatching method for the OnHalfMinute event. } procedure DoHalfMinute(TheTime: TDateTime); dynamic; public constructor Create(AOwner: TComponent); override; destructor Destroy; override; published // Define the actual property that will show in the Object Inspector property OnHalfMinute: TTimeEvent read FOnHalfMinute write FOnHalfMinute; end; implementation constructor TddgHalfMinute.Create(AOwner: TComponent); { The Create constructor, creates the TTimer instanced for FTimer. It then sets up the various properties of FTimer, including its OnTimer event handler which is TddgHalfMinute's FTimerTimer() method. Notice that FTimer.Enabled is set to true only if the component is running and not while the component is in design mode. } begin inherited Create(AOwner); // If the component is in design mode, do not enable FTimer. if not (csDesigning in ComponentState) then begin FTimer := TTimer.Create(self); FTimer.Enabled := True; // Set up the other properties, including the FTimer.OnTimer event handler FTimer.Interval := 500; FTimer.OnTimer := FTimerTimer; end; end; destructor TddgHalfMinute.Destroy; begin FTimer.Free; inherited Destroy; end; procedure TddgHalfMinute.FTimerTimer(Sender: TObject); { This method serves as the FTimer.OnTimer event handler and is assigned to FTimer.OnTimer at run-time in TddgHalfMinute's constructor. This method gets the system time, and then determines whether or not the time is on the minute, or on the half-minute. If either of these conditions are true, it calls the OnHalfMinute dispatching method, DoHalfMinute. } var DT: TDateTime; Temp: Word; begin DT := Now; // Get the system time. FOldSecond := FSecond; // Save the old second. // Get the time values, needed is the second value DecodeTime(DT, Temp, Temp, FSecond, Temp); { If not the same second when this method was last called, and if it is a half minute, call DoOnHalfMinute. } if FSecond <> FOldSecond then if ((FSecond = 30) or (FSecond = 0)) then DoHalfMinute(DT) end; procedure TddgHalfMinute.DoHalfMinute(TheTime: TDateTime); { This method is the dispatching method for the OnHalfMinute event. it checks to see if the user of the component has attached an event handler to OnHalfMinute and if so, calls that code. } begin if Assigned(FOnHalfMinute) then FOnHalfMinute(Self, TheTime); end; end.When creating your own events, you must determine what information you want to provide to users of your component as a parameter in the event handler. For example, when you create an event handler for the TEdit.OnKeyPress event, your event handler looks like the following code:
procedure TForm1.Edit1KeyPress(Sender: TObject; var Key: Char); begin end;Not only do you get a reference to the object that caused the event, but you also get a Charparameter specifying the key that was pressed. Deep in the Delphi VCL, this event occurred as a result of a WM_CHAR Win32 message that drags along some additional information relating to the key pressed. Delphi takes care of extracting the necessary data and making it available to component users as event handler parameters. One of the nice things about the whole scheme is that it enables component writers to take information that might be somewhat complex to understand and make it available to component users in a much more understandable and easy-to-use format.
Notice the var parameter in the preceding Edit1KeyPress() method. You might be wondering why this method wasn't declared as a function that returns a Char type instead of a procedure. Although method types can be functions, you shouldn't declare events as functions because it will introduce ambiguity; when you refer to a method pointer that is a function, you can't know whether you're referring to the function result or to the function pointer value itself. By the way, one function event in the VCL slipped past the developers from the Delphi 1 days, and now it must remain. This event is the TApplication.OnHelp event.
Looking at Listing 1, you'll see that we've defined the procedure type TOnHalfMinute as this:
TTimeEvent = procedure(Sender: TObject; TheTime: TDateTime) of object;This procedure type defines the procedure type for the OnHalfMinute event handler. Here, we decided that we want the user to have a reference to the object causing the event to occur and theTDateTime value of when the event occurred.
The FOnHalfMinute storage field is the reference to the user's event handler and is surfaced to the Object Inspector at design time through the OnHalfMinute property.
The basic functionality of the component uses a TTimer object to check the seconds value every half second. If the seconds value is 0 or 30, it invokes the DoHalfMinute() method, which is responsible for checking for the existence of an event handler and then calling it. Much of this is explained in the code's comments, which you should read over.
After installing this component to Delphi's Component Palette, you can place the component on the form and add the following event handler to the OnHalfMinute event:
procedure TForm1.ddgHalfMinuteHalfMinute(Sender: TObject; TheTime: TDateTime); begin ShowMessage('The Time is '+TimeToStr(TheTime)); end;This should illustrate how your newly defined event type becomes an event handler.
原文出处:http://www.informit.com/articles/article.aspx?p=26651
相关文章推荐
- js自定义事件及事件交互原理概述(一)
- jQuery基础(鼠标事件,表单事件,键盘事件,自定义事件 篇)
- 收藏大牛的代码(事件的原理是什么)
- js自定义事件及事件交互原理概述(二)
- delphi基础原理--BPL vs. DLL
- .NET基础扩展系列-事件的实现原理
- js自定义事件及事件交互原理概述(一)
- .NET基础扩展系列-事件的实现原理
- Delphi处理事件函数中的Sender: TObject代表什么?
- 转delphi中 formclose的事件 action:=cafree form:=nil分别是什么意思?
- js自定义事件及事件交互原理概述(二)
- javascript的事件处理(一)——基础原理
- js自定义事件及事件交互原理概述(一)
- 第一部份1:JMF基础原理与相关术语介绍 。。。。快速了解JMF有什么相关内容
- 二维码的基础原理是什么?
- delphi的事件中,都有(sender:Tobject)是什么意思?
- javascript的事件处理(一)——基础原理
- jQuery基础----06jQuery选择器和事件-事件之自定义事件
- delphi中 formclose的事件 action:=cafree form:=nil分别是什么意思?