• TControl与Windows消息


    TControl将系统消息转换成VCL事件,以将系统消息融入VCL中。鼠标的事件就是一个很好的例子,当我们单击鼠标时会产生鼠标的单击消息,而这个单击消息是怎么被处理并执行的呢?

    在Control单元中有这样的一段代码:

     1 TControl = class(TComponent)
     2 private
     3     ...
     4     FControlState: TControlState;    //状态    //TControlState = set of (csLButtonDown, csClicked,  .... , );
     5     ...
     6     FOnMouseDown: TMouseEvent;    //用以接受用户的定义的方法。
     7     ...
     8     procedure DoMouseDown(var Message: TWMMouse; Button: TMouseButton; Shift: TShiftState);
     9     ...
    10     procedure WMLButtonDown(var Message: TWMLButtonDown); message WM_LBUTTONDOWN;    //鼠标左键
    11     procedure WMRButtonDown(var Message: TWMRButtonDown); message WM_RBUTTONDOWN;    //鼠标右键
    12     procedure WMMButtonDown(var Message: TWMMButtonDown); message WM_MBUTTONDOWN;   //鼠标中间键
    13  protected
    14     procedure MouseDown(Button: TMouseButton; Shift: TShiftState; X, Y: Integer); dynamic;
    15     ...
    16     property OnMouseDown: TMouseEvent read FOnMouseDown write FOnMouseDown;
    17 end;

    TControl声明了一个OnMouseDown属性,该属性读写一个称为FOnMouseDown的事件指针。当我们需要处理一个按钮被按下的情况时,我们便会定义一个按钮按下的方法,并赋值给按钮OnMouseDown属性。此时,FOnMouseDown就会指向这个用户定义的方法。

    当我们左键按下鼠标时候,TObject会调用Dispatch()方法会分发WM_LBUTTIONDOWN消息分发,然后进入相应的消息处理函数。如下:

    1 procedure TControl.WMLButtonDown(var Message: TWMLButtonDown);
    2 begin
    3   SendCancelMode(Self);
    4   inherited;
    5   if csCaptureMouse in ControlStyle then MouseCapture := True; 
    6   if csClickEvents in ControlStyle then Include(FControlState, csClicked);
    7   DoMouseDown(Message, mbLeft, []);
    8 end;

    如果是单击事件,则在FControlState中添加csClicked。并且跳转到DoMouseDown()方法中。

     1 procedure TControl.DoMouseDown(var Message: TWMMouse; Button: TMouseButton;
     2   Shift: TShiftState);
     3 begin
     4   if not (csNoStdEvents in ControlStyle) then
     5     with Message do
     6       if (Width > 32768) or (Height > 32768) then
     7         with CalcCursorPos do
     8           MouseDown(Button, KeysToShiftState(Keys) + Shift, X, Y)
     9       else
    10         MouseDown(Button, KeysToShiftState(Keys) + Shift, Message.XPos, Message.YPos);
    11 end;

    在DoMouseDown()中进行一些必要的处理工作后,就会调用MouseDown();

    1 procedure TControl.MouseDown(Button: TMouseButton;
    2   Shift: TShiftState; X, Y: Integer);
    3 begin
    4   if Assigned(FOnMouseDown) then FOnMouseDown(Self, Button, Shift, X, Y);
    5 end;

    在MouseDown()中,就会通过FOnMouseDown事件指针去执行用户定义的代码。此时就完成了从一个WM_LBUTTIONDOWN消息转换成相应的代码过程。

    另外,值得注意的是,鼠标的Click事件是没有相应的消息的,鼠标的单击事件被包含在WM_LBUTTIONDOWN消息中,而鼠标的双击事件的消息是WM_LBUTTONDBLCLK消息。而,我们如果要单击鼠标,会先处理OnMouseDown()事件,然后再处理OnClick()事件。并且,如果我们双击鼠标,首先先处理OnMouseDown()事件,然后再处理OnDblClick()事件。这一点很好被验证:

     1 procedure TForm1.FormClick(Sender: TObject);
     2 begin
     3   ShowMessage('click');
     4 end;
     5 
     6 procedure TForm1.FormDblClick(Sender: TObject);
     7 begin
     8   ShowMessage('dblclick');
     9 end;
    10 
    11 procedure TForm1.FormMouseDown(Sender: TObject; Button: TMouseButton;
    12   Shift: TShiftState; X, Y: Integer);
    13 begin
    14   ShowMessage('Down');
    15 end;

    如果我们不注释第14行,那么无论我们如何点击鼠标,都只能处理OnMouseDown()事件,然后ShowMessage()并得到焦点,OnClick()或OnDblCLick事件就不会被执行到。同样,当我们双击鼠标的时候,首先会ShowMessage('click')。

  • 相关阅读:
    MySQL · 引擎特性 · InnoDB 事务锁简介
    锁大全与 GDB调试
    docker(4):coreos+docker+rancher真厉害
    TIDB ---NEW SQL
    Linux的内存回收和交换
    TLS握手优化详解
    北风网JAVA 大数据培训
    MySQL 5.7 深度解析: JSON数据类型使用
    MySQL 5.7 深度解析: 临时表空间
    在Linux最大打开文件数限制下 MySQL 对参数的调整
  • 原文地址:https://www.cnblogs.com/Blogs-young-chan/p/5719642.html
Copyright © 2020-2023  润新知