本人最近在写一个自定义控件,其中有一功能是:在捕获鼠标左键按下消息的同时检测ctrl键的状态,按下和没按的处理不一样。我写了一个鼠标左键按下的处理过程,希望在此过程内获取ctrl键的状态
procedure WM_Click(var Msg: TWMLButtonDown); message WM_LBUTTONDOWN;//鼠标单击通过查找资料,得知有个api函数GetKeyState可以实现,但是由于这段时间正在学习vcl,想看看vcl是怎么实现的,结果发现其不是使用该函数,且很多细节看不太懂,现罗列出来,望高人指点:----------------------------------------------------------------------------------------
以下代码截自tctrol,众所周知,OnMouseDown的事件处理大致如下WMLButtonDown->DoMouseDown->MouseDownWMLButtonDown(var Message: TWMLButtonDown);
DoMouseDown(var Message: TWMMouse; Button: TMouseButton;  Shift: TShiftState);
MouseDown(Button: TMouseButton; Shift: TShiftState; X, Y: Integer);这三个过程的参数是逐渐增加,=======我的问题就是这个增加的参数是怎么来的?=======请看疑问注释:--------------------------------------------------------------------------------
procedure TControl.MouseDown(Button: TMouseButton;
  Shift: TShiftState; X, Y: Integer);
begin
  if Assigned(FOnMouseDown) then FOnMouseDown(Self, Button, Shift, X, Y);
end;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) {
KeysToShiftState(Keys)函数原型在后面[功能就是取得哪些功能键被按下吧,shift参数的实际内容就是在这增加的],+shift,从调用它的DoMouseDown(Message, mbLeft, [])语句来看,实参在此已经是空集了,还加上有何用意? 它的keys参数是哪里来的,找遍整个单元也没见哪里有声明过, X,Y也是,不知从何而来?
}      else
        MouseDown(Button, KeysToShiftState(Keys) + Shift, Message.XPos, Message.YPos);
end;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;
-------------------------------------------------------------------------
function KeysToShiftState(Keys: Word): TShiftState;
begin
  Result := [];
  if Keys and MK_SHIFT <> 0 then Include(Result, ssShift);
  if Keys and MK_CONTROL <> 0 then Include(Result, ssCtrl);
  if Keys and MK_LBUTTON <> 0 then Include(Result, ssLeft);
  if Keys and MK_RBUTTON <> 0 then Include(Result, ssRight);
  if Keys and MK_MBUTTON <> 0 then Include(Result, ssMiddle);
  if GetKeyState(VK_MENU) < 0 then Include(Result, ssAlt);
end;

解决方案 »

  1.   

    基本过程如下  TMouseEvent = procedure(Sender: TObject; Button: TMouseButton;
        Shift: TShiftState; X, Y: Integer) of object; //声明property OnMouseDown: TMouseEvent read FOnMouseDown write FOnMouseDown;FOnMouseDown: TMouseEvent;  定义
    procedure TControl.MouseDown(Button: TMouseButton;
      Shift: TShiftState; X, Y: Integer);  //调用
    begin
      if Assigned(FOnMouseDown) then FOnMouseDown(Self, Button, Shift, X, Y); //对应上 
    end;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);
         //调用MouseDown
    end; procedure TForm1.FormMouseDown(Sender: TObject; Button: TMouseButton;
      Shift: TShiftState; X, Y: Integer);
    begin
      //处理消息
    end;
    当MouseDown按下了后,系统告诉程序鼠标按下
    TControl.DoMouseDown->调用MouseDown->调用FOnMouseDown->TMouseEvent-> 找到代码FormMouseDown
    开始执行你的代码
      

  2.   

    to  cdsgajxlp(起名很难): 你说的这些我已经写出来了,只是没那么详细,我的问题不是在于它的处理机制,而是机制内的细节问题:{
    KeysToShiftState(Keys)函数原型在后面[功能就是取得哪些功能键被按下吧,shift参数的实际内容就是在这增加的],+shift,从调用它的DoMouseDown(Message, mbLeft, [])语句来看,实参在此已经是空集了,还加上有何用意? 它的keys参数是哪里来的,找遍整个单元也没见哪里有声明过, X,Y也是,不知从何而来?
    }
    ---------------------------------------------------------------
    昨天又看到了 TControl.WndProc(var Message: TMessage)过程的代码,其实它就是用GetKeyState来获取功能键状态的。
      

  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, []);//mbLeft  
    end;procedure TControl.WMLButtonDblClk(var Message: TWMLButtonDblClk);
    begin
      SendCancelMode(Self);
      inherited;
      if csCaptureMouse in ControlStyle then MouseCapture := True;
      if csClickEvents in ControlStyle then DblClick;
      DoMouseDown(Message, mbLeft, [ssDouble]); //不空吧
    end;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;MouseDown(Button, KeysToShiftState(Keys) + Shift, Message.XPos, Message.YPos); //不就有x,y了
      

  4.   

    此贴跟以前发的一样,没什么收获;看来问题还是得自己解决,看看李维 inside vcl 吧。
    放分,谢谢几位关注。