Delphi is a brand-new WINDOWS programming development tool provided by Borland. Because it uses the flexible and reusable object-oriented Pascal (object-oriented pascal) language and has a powerful database engine (BDE), fast code The compiler also provides many excellent components. It is favored by the majority of programmers. It stands out among many programming languages (such as VB, PowerBuilder, Powerpoint, etc.).
One of the advantages of DELPHI over other programming languages (such as VB4.0) is that messages can be customized in DELPHI and can be processed directly. This is for those who want to write their own components (Component), or who want to intercept and filter messages. It is essential for users. Because writing components generally requires processing corresponding messages. The following is an introduction to the message processing mechanism in Delphi.
1. Message delivery in DELPHI VCL
Each VCL (Visual Component Library) component (such as Tbutton, Tedit, etc.) in Delphi has an inherent message processing mechanism. The basic point is that the component class receives certain messages and sends them to the appropriate processing method. If there is no specific processing method, the default message processing handle is called. Among them, mainwndPRoc is a static method defined in the Twincontrol class and cannot be overloaded (Override). It does not process the message directly, but leaves it to the wndproc method for processing, and provides an exception handling module for the wndproc method. The Mainwndproc method is declared as follows:
procedure MainWndProc(var Message: TMessage);
Wndproc is a virtual method defined in the Tcontrol class, which calls the dispatch method to distribute messages. The wndproc method is declared as follows:
procedure WndProc(var Message: TMessage); virtual;
The dispatch method is defined in the Tobject root class and is declared as follows:
procedure Tobject.dispatch(var Message); The message parameter passed to dispatch must be a record type, and the first entry point in this record must be a cardinal type field (field), which contains the message of the message to be distributed Number. For example:
type
Tmessage=record
Msg:cardinal;
wparam:Word;
lparam:longint; .
result:longint;
end;
The Dispatch method will call the handle method of the last generation class of the component that handles this message based on the message number. If there is no handler corresponding to this message in this component and its ancestor class, the Dispatch method will call the Defaulthandler method. The Defaulthandler method is The virtual method defined in Tobject is declared as follows:
procedure Defaulthandler(var Message);virtual;
The Defaulthandler method in the Tobject class only implements a simple return without any processing of the message. We can implement the default processing of the message in the subclass by overloading this virtual method. For components in the VCL, Its Defaulthandler method will start the windows API function Defwindowproc to process the message.
2. Message processing handle in DELPHI
In DELPHI, users can customize messages and message processing handles. The definition of message processing handles has the following principles:
The message processing handle method must be a procedure, and can only pass one Tmessage type variable parameter.
The method declaration must be followed by a message command, followed by a message label (integer constant) between 0 and 32767.
The message handler method does not need to use the override command to explicitly indicate overriding a message handler of the ancestor. In addition, it is generally declared in the protected or private area of the component.
In the message processing handle, the user generally processes the message first, and finally uses the inherited command to call the processing handle corresponding to this message in the ancestor class (in some cases, it may be the opposite). Because the processing handle of this message in the ancestor class may be The name and parameter type are unclear, and calling the command inherited can avoid this trouble. Similarly, if there is no handler corresponding to this message in the ancestor class, inherited will automatically call the Defaulthandler method. (Of course, if you want to block this message, There is no need to use the inherited command).
The message handler method is declared as:
procedure Mymsgmethod(var message:Tmessage); message Msgtype;
Similarly, users can also define their own messages. User-defined messages should start with WM_USER.
Examples of custom messages and message processing handles are as follows:
const my_paint=Wm_user+1;
type
Tmypaint=record
msgid:cardinal;
msize:word;
mcolor:longint;
msgresult:longint;
end;
type
Tmycontrol=class(TCustomControl)
protected
procedure change(var message:Tmypaint); message my_paint;
.....
end;
...
procedure Tmycontrol.change(var message:Tmypaint);
begin
size:=message.msize; {Set Tmybutton size attribute}
color:=message.mcolor; {Set Tmybutton color attribute}
{do something else}
inherited; { Handed over to Tcustomcontrol}
end;
3. Filter messages
Filtering messages is also called message trap. Under certain circumstances, users may need to block certain messages or intercept certain messages for processing. From the above introduction, we can see that there are generally three ways to filter messages: (1). Overload the virtual method wndproc inherited by the component. (2). Write a message processing handle for a certain message. (3). Overload the virtual method Defhandler inherited by the component , where messages are processed. The most commonly used method is method (2), which has been introduced in the previous section. Method (1) is similar to method (3). Here we only briefly introduce method (1).
The general process of overloading the virtual method wndproc is as follows:
procedure Tmyobject.wndproc(var message:Tmessage);
begin
{... Determine whether this message should be processed..}
inherited wndproc(message);
{Unprocessed messages are handled by the parent wndproc method}
end;
It can be seen from this that the advantage of processing messages in the wndproc method is that it can filter the entire range of messages without having to specify a processing handle for each message. In fact, it is used in the Tcontrol component to filter and process all mouse messages. (From WM_mousefirst to WM_mouselast, as shown in the following code). It can also be used to prevent certain messages from being sent to the handler.
procedure TControl.WndProc(var Message: TMessage);
begin
if (Message.Msg>=WM_MOUSEFIRST) and
(Message.Msg <= WM_MOUSELAST)
then
if Dragging then {Handle drag event}
DragMouseMsg(TWMMouse(Message))
else
... {handle other mouse messages}
end;
Dispatch(Message);
{Otherwise send the message normally}
end;
The following example is a simple custom component example:
The Tmyedit class is a new class derived from the Tedit class. Its characteristic is that it cannot obtain focus during operation and cannot be input by the keyboard (somewhat similar to the Tlabel component). We can filter out the WM_setfocus and WM_mousemove messages in its wndproc method and perform To achieve the above requirements, the source program is as follows:
unit myedit;
interface
uses
Windows, Messages, SysUtils, Classes, Graphics,
Controls, Forms, Dialogs,
StdCtrls;
type
Tmyedit = class(TEdit)
private
{Private declarations}
protected
{ Protected declarations }
{ other fields and methods}
procedure wndproc(var message:Tmessage);override;
public
{Public declarations}
published
{ Published declarations }
end;
procedure Register;
implementation
procedure Register;
begin
RegisterComponents('Samples', [Tmyedit]);
end;
procedure Tmyedit.wndproc(var message:tmessage);
begin
if message.msg=wm_mousemove then
begin
cursor:=crarrow;
{Set the cursor to crarrow instead of the default crBeam cursor}
exit;
end;
if message.msg=wm_SetFocus then exit;
{Shield the WM_setfocus message and prevent the Tmyedit control from obtaining input focus}
inherited wndproc(message);
{Other messages are handed over to the parent wndproc for processing}
end;
end.
You can add Tmyedit to the Component Palette to test its performance.
As can be seen from the above introduction, only by understanding the message processing mechanism in Delphi VCL, mastering the methods and timing of processing various messages (using various tools if necessary, such as winsight32, spy, etc.), and combining the characteristics of the OOP language , we can compile high-quality components. This, of course, requires readers to constantly explore and accumulate experience in practice.