TControl作为控件类的根类提供的服务:
1)TControl控件基本信息
TControl开始加入控件的基本信息并使用持久化机制保存信息。TControl声明的Left、Top等控件信息并使用Published关键字输出以便让客户端存取。这些控件信息会自动被持久化。

核心库类之TControl TControl = class(TComponent)
核心库类之TControl  
private
核心库类之TControl    FParent: TWinControl;
核心库类之TControl    FWindowProc: TWndMethod;
核心库类之TControl    FLeft: 
Integer;
核心库类之TControl    FTop: 
Integer;
核心库类之TControl    FWidth: 
Integer;
核心库类之TControl    FHeight: 
Integer;
核心库类之TControl    FControlStyle: TControlStyle;
核心库类之TControl    FControlState: TControlState;
核心库类之TControl    核心库类之TControl
核心库类之TControl published
核心库类之TControl    
property LeftInteger read FLeft write SetLeft;
核心库类之TControl    
property Top: Integer read FTop write SetTop;
核心库类之TControl    
property Width: Integer read FWidth write SetWidth;
核心库类之TControl    
property Height: Integer read FHeight write SetHeight;
核心库类之TControl    
property Cursor: TCursor read FCursor write SetCursor default crDefault;
核心库类之TControl    
property Hint: string read FHint write FHint stored IsHintStored;
核心库类之TControl    
property HelpType: THelpType read FHelpType write FHelpType default htContext;
核心库类之TControl    
property HelpKeyword: String read FHelpKeyword write SetHelpKeyword stored IsHelpContextStored;
核心库类之TControl    
property HelpContext: THelpContext read FHelpContext write SetHelpContext stored IsHelpContextStored default 0;
核心库类之TControl
end;

FParent: TWinControl代表TControl和TWinControl有紧耦合。
2)基础资源服务
  控件需要使用光标、文字、颜色、字体以及其他的资源,TControl必须具备这些资源的支持,相关属性:

核心库类之TControl    FParentFont: Boolean;
核心库类之TControl    FParentColor: 
Boolean;
核心库类之TControl    FAlign: TAlign;
核心库类之TControl    FDragMode: TDragMode;
核心库类之TControl    FText: PChar;
核心库类之TControl    FFont: TFont;
核心库类之TControl    FColor: TColor;
核心库类之TControl    FCursor: TCursor;

除了资源属性,当外界改变控件使用的资源时,TControl提供响应资源事件的方法,CM-XXXChanged方法是和资源改变相关的方法。

核心库类之TControl    procedure CMFontChanged(var Message: TMessage); message CM_FONTCHANGED;
核心库类之TControl    procedure CMColorChanged(var Message: TMessage); message CM_COLORCHANGED;

 

核心库类之TControlprocedure TControl.CMFontChanged(var Message: TMessage);
核心库类之TControlbegin
核心库类之TControl  Invalidate;
核心库类之TControl
end;
核心库类之TControl
核心库类之TControlprocedure TControl.CMColorChanged(var Message: TMessage);
核心库类之TControlbegin
核心库类之TControl  Invalidate;
核心库类之TControl
end;

TControl.Invalidate调用了TControl.InvalidateControl来重绘控件区域,TControl.InvalidateControl最后调用了Windows API的InvalidateRect莱进行重绘工作。

核心库类之TControlprocedure TControl.Invalidate;
核心库类之TControlbegin
核心库类之TControl  InvalidateControl(Visible, csOpaque in ControlStyle);
核心库类之TControl
end;
核心库类之TControl
核心库类之TControlprocedure TControl.InvalidateControl(IsVisible, IsOpaque: 
Boolean);
核心库类之TControlvar
核心库类之TControl  Rect: TRect;
核心库类之TControl
核心库类之TControl  
function BackgroundClipped: Boolean;
核心库类之TControl  var
核心库类之TControl    R: TRect;
核心库类之TControl    List: TList;
核心库类之TControl    I: 
Integer;
核心库类之TControl    C: TControl;
核心库类之TControl  begin
核心库类之TControl    Result :
= True;
核心库类之TControl    List :
= FParent.FControls;
核心库类之TControl    I :
= List.IndexOf(Self);
核心库类之TControl    
while I > 0 do
核心库类之TControl    begin
核心库类之TControl      Dec(I);
核心库类之TControl      C :
= List[I];
核心库类之TControl      
with C do
核心库类之TControl        
if C.Visible and (csOpaque in ControlStyle) then
核心库类之TControl        begin
核心库类之TControl          IntersectRect(R, Rect, BoundsRect);
核心库类之TControl          
if EqualRect(R, Rect) then Exit;
核心库类之TControl        
end;
核心库类之TControl    
end;
核心库类之TControl    Result :
= False;
核心库类之TControl  
end;
核心库类之TControl
核心库类之TControlbegin
核心库类之TControl  
if (IsVisible or (csDesigning in ComponentState) and
核心库类之TControl    
not (csNoDesignVisible in ControlStyle)) and (Parent <> nil) and
核心库类之TControl    Parent.HandleAllocated 
then
核心库类之TControl  begin
核心库类之TControl    Rect :
= BoundsRect;
核心库类之TControl    InvalidateRect(Parent.Handle, @Rect, 
not (IsOpaque or
核心库类之TControl      (csOpaque in Parent.ControlStyle) 
or BackgroundClipped));
核心库类之TControl  
end;
核心库类之TControl
end;

注意:Invalidate被声明为虚拟方法。procedure Invalidate; virtual;
3)处理鼠标的服务
控件需要处理鼠标事件,WMXXButtonXXXX等方法是TControl提供的基础鼠标服务,

核心库类之TControl  procedure WMLButtonDown(var Message: TWMLButtonDown); message WM_LBUTTONDOWN;
核心库类之TControl    procedure WMNCLButtonDown(var Message: TWMNCLButtonDown); message WM_NCLBUTTONDOWN;
核心库类之TControl    procedure WMRButtonDown(var Message: TWMRButtonDown); message WM_RBUTTONDOWN;
核心库类之TControl    procedure WMMButtonDown(var Message: TWMMButtonDown); message WM_MBUTTONDOWN;
核心库类之TControl    procedure WMLButtonDblClk(var Message: TWMLButtonDblClk); message WM_LBUTTONDBLCLK;
核心库类之TControl    procedure WMRButtonDblClk(var Message: TWMRButtonDblClk); message WM_RBUTTONDBLCLK;
核心库类之TControl    procedure WMMButtonDblClk(var Message: TWMMButtonDblClk); message WM_MBUTTONDBLCLK;
核心库类之TControl    procedure WMMouseMove(var Message: TWMMouseMove); message WM_MOUSEMOVE;
核心库类之TControl    procedure WMLButtonUp(var Message: TWMLButtonUp); message WM_LBUTTONUP;
核心库类之TControl    procedure WMRButtonUp(var Message: TWMRButtonUp); message WM_RBUTTONUP;
核心库类之TControl    procedure WMMButtonUp(var Message: TWMMButtonUp); message WM_MBUTTONUP;
核心库类之TControl    procedure WMMouseWheel(var Message: TWMMouseWheel); message WM_MOUSEWHEEL;
核心库类之TControl    procedure WMCancelMode(var Message: TWMCancelMode); message WM_CANCELMODE;


如果TControl的派生类没有定义处理鼠标的方法,那么TControl便会负责处理鼠标事件。

核心库类之TControlprocedure TControl.WMLButtonDown(var Message: TWMLButtonDown);
核心库类之TControlbegin
核心库类之TControl  SendCancelMode(Self);
核心库类之TControl  inherited;
核心库类之TControl  
if csCaptureMouse in ControlStyle then MouseCapture := True;
核心库类之TControl  
if csClickEvents in ControlStyle then Include(FControlState, csClicked);
核心库类之TControl  DoMouseDown(Message, mbLeft, []);
核心库类之TControl
end;


4)处理消息和事件的服务
控件要处理事件和消息,要加入响应外界事件的处理机制,这就是

核心库类之TControl    procedure WndProc(var Message: TMessage); virtual;
核心库类之TControl    procedure DefaultHandler(var Message); override;


5)控件重绘服务
控件重绘事控件类最需要的核心服务,因为控件可以移动,改变字体、颜色、大小等,当这些事件发生时控件都需要进行重绘工作。采用虚拟方法。
TControl 提供了三个相关的虚拟方法来提供控件重绘的功能,分别是

核心库类之TControl    procedure Repaint; virtual;
核心库类之TControl    procedure Invalidate; virtual;
核心库类之TControl    procedure Update; virtual;


1.TControl与Windows消息的封装
TObject提供了最基本的消息分发和处理的机制,而VCL真正对Windows系统消息的封装则是在TControl中完成的。
TControl将消息转换成VCL的事件,以将系统消息融入VCL框架中。
消息分发机制在4.2节已经介绍过,那么系统消息是如何变成事件的呢?
现在,通过观察TControl的一个代码片段来解答这个问题。在此只以鼠标消息变成鼠标事件的过程来解释,其余的消息封装基本类似。
先摘取TControl声明中的一个片段:
TControl = class(TComponent)
Private
  ……
  FOnMouseDown: TMouseEvent;
  ……
  procedure DoMouseDown(var Message: TWMMouse; Button: TMouseButton;
  Shift: TShiftState);
  ……
  procedure MouseDown(Button: TMouseButton; Shift: TShiftState;
  X, Y: Integer); dynamic;
  ……
  procedure WMLButtonDown(var Message: TWMLButtonDown); message
WM_LBUTTONDOWN;
  procedure WMRButtonDown(var Message: TWMRButtonDown); message
WM_RBUTTONDOWN;
  procedure WMMButtonDown(var Message: TWMMButtonDown); message
WM_MBUTTONDOWN;
  ……
protected
  ……
  property OnMouseDown: TMouseEvent read FOnMouseDown write FOnMouseDown;
  ……
end;
这段代码是TControl组件类的声明。
TControl声明了一个OnMouseDown属性,该属性读写一个称为FOnMouseDown的事件指针。因此,FOnMouseDown会指向OnMouseDown事件的用户代码。
TControl声明了WMLButtonDown、WMRButtonDown、WMMButtonDown 3个消息 处理函数,它们分别处理WM_LBUTTONDOWN、WM_RBUTTONDOWN、WM _MBUTTONDOWN 3个Windows消息,对应于鼠标的左键按下、右键按下、中键按下3个硬件事件。
另外,还有一个DoMouseDown()方法和一个MouseDown()的dynamic方法,它们与消息处理函数之间2是什么样的关系呢?
现在,就来具体看一下这些函数的实现。
这里是3个消息的处理函数:
procedure TControl.WMLButtonDown(var Message: TWMLButtonDown);
begin
  SendCancelMode(Self);
  inherited;
  if csCaptureMouse in ControlStyle then
    MouseCapture := True;
  if csClickEvents in ControlStyle then
    Include(FControlState, csClicked);
  DoMouseDown(Message, mbLeft, []);
end;
procedure TControl.WMRButtonDown(var Message: TWMRButtonDown);
begin
  inherited;
  DoMouseDown(Message, mbRight, []);
end;

procedure TControl.WMMButtonDown(var Message: TWMMButtonDown);
begin
  inherited;
  DoMouseDown(Message, mbMiddle, []);
end;
当TObject.Dispatch()将WM_LBUTTONDOWN消息、WM_RBUTTONDOWN消息或WM_MBUTTONDOWN消息分发给TControl的派生类的实例后,WMLButtonDown()、WMRButtonDown()或WMMButtonDown()被执行,然后它们都有类似这样
DoMouseDown(Message, mbRight, []);的代码来调用DoMouseDown():
procedure TControl.DoMouseDown(var Message: TWMMouse; Button:
TMouseButton; Shift: TShiftState);
begin
  if not (csNoStdEvents in ControlStyle) then
  with Message do
    if (Width > 32768) or (Height > 32768) then
  with CalcCursorPos do
    MouseDown(Button, KeysToShiftState(Keys) + Shift, X, Y)
  else
   MouseDown(Button,KeysToShiftState(Keys) + Shift,Message.XPos,Message.Ypos);
end;
在DoMouseDown()中进行一些必要的处理工作后(特殊情况下重新获取鼠标位置),就会调
MouseDown():
procedure TControl.MouseDown(Button: TMouseButton;Shift: TShiftState; X, Y: Integer);
begin
  if Assigned(FOnMouseDown) then
    FOnMouseDown(Self, Button, Shift, X, Y);
end;

在MouseDown()中,才会通过FOnMouseDown事件指针真正去执行用户定义的OnMouseDown事件的代码。
由此,完成了Windows系统消息到VCL事件的转换过程。
因此,从TControl派生的类都可以拥有OnMouseDown事件,只不过该事件属性在TControl中被定义成protected,只有其派生类可见,并且在派生类中可以自由选择是否公布这个属性。要公布该属性只需要简单地将其声明为published即可。如:
TMyControl = class(TControl)
published
  property OnMouseDown;
end;
这些函数过程的调用关系: Dispatch(WM_LBUTTONDOWN)-〉 WMMouseDown() -〉DoMouseDown() -〉MouseDown() -〉程序员的OnMouseDown事件代码;
说明了WM_LBUTTONDOWN消息到OnMouseDown事件的转换过程
在此,只是以OnMouseDown事件为例。其实,VCL对Windows各个消息的封装大同小异,以此一例足以说明事件模型的原理。
另外,值得注意的是,在上例中的MouseDown()函数是一个dynamic方法,因此可以通过在TControl派生类中覆盖MouseDown()来处理自己所编写组件的鼠标按下事件,然后通过inherited;语句调用TControl的MouseDown()来执行使用组件的程序员所编写的OnMouseDown的代码。

相关文章:

  • 2021-11-30
  • 2022-12-23
  • 2021-05-03
  • 2022-01-21
  • 2022-12-23
  • 2021-10-03
  • 2021-09-14
  • 2021-09-14
猜你喜欢
  • 2022-12-23
  • 2022-12-23
  • 2022-12-23
  • 2021-10-27
  • 2022-12-23
  • 2021-07-25
  • 2021-04-18
相关资源
相似解决方案