DELPHI盒子
!实时搜索: 盒子论坛 | 注册用户 | 修改信息 | 退出
检举帖 | 全文检索 | 关闭广告 | 捐赠
技术论坛
 用户名
 密  码
自动登陆(30天有效)
忘了密码
≡技术区≡
DELPHI技术
lazarus/fpc/Free Pascal
移动应用开发
Web应用开发
数据库专区
报表专区
网络通讯
开源项目
论坛精华贴
≡发布区≡
发布代码
发布控件
文档资料
经典工具
≡事务区≡
网站意见
盒子之家
招聘应聘
信息交换
论坛信息
最新加入: fhc2004
今日帖子: 12
在线用户: 20
导航: 论坛 -> 论坛精华贴 斑竹:liumazi,iamdream  
作者:
男 qyhyf2000 (枫) ★☆☆☆☆ -
普通会员
2003/5/2 20:20:47
标题:
请问在delphi中如果判断鼠标的指针已离开了一个控件或是离开了窗体?? 浏览:6364
加入我的收藏
楼主: 如题,我想在鼠标离开时激活一个事件
----------------------------------------------
-
作者:
女 123 (猪猪) ★☆☆☆☆ -
盒子活跃会员
2003/5/2 22:00:17
1楼: 用 GetCursorPos() 函数.
----------------------------------------------
-
作者:
男 qyhyf2000 (枫) ★☆☆☆☆ -
普通会员
2003/5/2 23:06:25
2楼: 能否给出一个例子呢?
----------------------------------------------
-
作者:
男 yangjingzun (yjz) ★☆☆☆☆ -
普通会员
2003/5/3 17:55:52
3楼: 加入一TTimer控件,然后在Timer事件中判断当前的鼠标是否在窗体之内即可。
----------------------------------------------
-
作者:
男 liumazi (刘麻子) ★☆☆☆☆ -
大善人会员
2004/9/19 12:03:51
4楼:      c++ builder里四种处理“鼠标离开窗体”事件的方法    hhdsq(原作) 
  
关键字     鼠标,窗体,消息 
  


       在处理窗体消息的时候,我想不少人都会碰到鼠标离开窗体的消息(下面称之为
MouseLeave)。在C++ Builder里,并没有直接提供处理这种消息的方法,需要我们自己动
手来做。通过参考一些资料,我发现在C++ Builder里面处理MouseLeave,不外乎以下四种
方法,现写出来供大家参考。如果有什么不对之处,请指正。

(一)、笨拙的Timer

       每每提到捕捉鼠标离开窗体的消息的时候,也许有人就会马上想到用Timer来处理。
不错,这种方法很简单,也确实有效。只须在Timer的OnTimer事件中判断鼠标所处位置的坐
标是否在窗体内就可以了,详细代码如下:

void __fastcall TForm1::Timer1Timer(TObject *Sender)
{
        POINT pt;
        GetCursorPos(&pt);                   //得到鼠标的坐标
        RECT rect;
        GetWindowRect(Handle,&rect);  //得到窗体的矩形范围
        if(!PtInRect(rect,pt))                 //判断鼠标的坐标是否在窗体的矩形范围内

                Caption="out";
        else
                Caption="in";
}

       为什么我要说是笨拙的Timer呢?原因有二:其一、OnTimer是优先级别比较低的消
息,从严格意义上讲,上面这种做法并不精准。如果系统正在处理一大堆级别比较高的消息
,那我们就无法及时获得MouseLeave消息。其二、Timer是比较宝贵的系统资源,用在
MouseLeave上面似乎有些浪费了,因为我们还有更好的方法来做同样的事情。

(二)、霸道的SetCapture()

        SetCapture()可以让指定的窗体捕获所有鼠标消息,当然也包括MouseLeave了:

void __fastcall TForm1::FormMouseMove(TObject *Sender, TShiftState Shift,
      int X, int Y)
{
                Caption="in";
                SetCapture(Handle);
                TPoint pt(X,Y);
                TRect rect;
                rect=GetClientRect();
                if (!PtInRect(rect,pt))
                {
                        ReleaseCapture();
                        Caption="out";
                }
}

       不过这种方法太过于霸道了,因为SetCapture()将所有的鼠标消息据为己有。虽然
在捕获了MouseLeave以后已经ReleaseCapture了,但是在捕获过程中,你却无法对其他的
鼠标消息做出反应。不信?你不妨在窗体在多放一个Button控件,再运行点点看?:)

(三)、受限的TrackMouseEvent()

       MSDN上面说,TrackMouseEvent()可以让指定的窗体接受WM_MOUSELEAVE消息。但是
在接受消息以后如果还要继续接受WM_MOUSELEAVE消息,必须重新调用TrackMouseEvent():

//---------------------------------------------------------------------------
__fastcall TForm1::TForm1(TComponent* Owner)
        : TForm(Owner)
{
        MouseTrack=false;   //TForm1的私有变量,检测鼠标是否已经被Track
}
//---------------------------------------------------------------------------
void __fastcall TForm1::WndProc(TMessage& Message)          //重载WndProc
{
        if (Message.Msg==WM_MOUSELEAVE)   //在这里捕获WM_MOUSELEAVE消息
        {
                Caption="out";
                MouseTrack=false;      //鼠标Track已经完成
        }
        TForm::WndProc(Message);
}
//---------------------------------------------------------------------------
void __fastcall TForm1::FormMouseMove(TObject *Sender, TShiftState Shift,
      int X, int Y)
{
        Caption="in";
        if (!MouseTrack)
        {
                TRACKMOUSEEVENT tt;
                tt.cbSize=sizeof(tt);
                tt.dwFlags=TME_LEAVE;
                tt.hwndTrack=Handle;
                TrackMouseEvent(&tt);
                MouseTrack=true;                  //开始鼠标Track
        }
}
//---------------------------------------------------------------------------

       这种方法很好用,唯一的缺点是可能不支持Win98(具体支不支持我也没有做过实
验,哪位兄弟有Win98的帮我测试一下)。在Win2000的环境下,我推荐用这种方法,:)

(四)、未知的CM_MOUSELEAVE

       在CSDN论坛里经常看到有人说可以通过捕获CM_MOUSELEAVE消息来达到同样的效果。不过根据我的
测试,CM_MOUSELEAVE在控件上面工作得很好,可以用来捕获鼠标离开控件的消息。但用在
窗体上似乎就不灵验了,可能我自己没有做对吧。如果有哪位大虾知道该怎么用,请告知小
弟一声,我将感激不尽。

以上代码均在Win2k Professional+bcb6.0环境中编译成功。
----------------------------------------------
好好学习,天天上网。
作者:
男 liumazi (刘麻子) ★☆☆☆☆ -
大善人会员
2004/11/25 22:26:06
5楼: 我试验的结果是,在98也支持TrackMouseEvent的.我好几个程序都用了这个方法.
另外,有时我也在计时器中使用GetCursorPos来判断当前鼠标所在窗体,代码为:
var
  ItemPoint: TPoint;
  hwCursor: LongWord;
begin
  GetCursorPos(ItemPoint);
  hwCursor := WindowFromPoint(ItemPoint);
  if (hwCursor = 句柄) then .....;
end;
----------------------------------------------
好好学习,天天上网。
作者:
男 weiwei123 (weiwei) ★☆☆☆☆ -
普通会员
2006/11/23 19:41:04
6楼: unit Unit1;

interface

uses
  Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,Dialogs, StdCtrls, ExtCtrls;

type
  TForm1 = class(TForm)
    Button1: TButton;
    Label1: TLabel;
    procedure FormCreate(Sender: TObject);
    procedure FormMouseMove(Sender: TObject; Shift: TShiftState; X,
      Y: Integer);
  private
    { Private declarations }
    bMouseTrack:Boolean;
    procedure WndProc(var Msg:TMessage);override;
  public
    { Public declarations }
  end;

var
  Form1: TForm1;

implementation

{$R *.dfm}

procedure TForm1.FormCreate(Sender: TObject);
begin
  bMouseTrack:=false;
end;

procedure TForm1.WndProc(var Msg: TMessage);
begin
  if (Msg.Msg=WM_MOUSELEAVE) then  //在这里捕获WM_MOUSELEAVE消息
    begin
      Label1.Caption:='out';
      bMouseTrack:=false;      //鼠标Track已经完成
    end;
  inherited;
end;

procedure TForm1.FormMouseMove(Sender: TObject; Shift: TShiftState; X,
  Y: Integer);
var
  tt:TagTRACKMOUSEEVENT;
begin
  Label1.Caption:='in';
  if not bMouseTrack then
     begin
        tt.cbSize:=sizeof(tt);
        tt.dwFlags:=TME_LEAVE;
        tt.hwndTrack:=Handle;
        TrackMouseEvent(tt);
        bMouseTrack:=true;          //开始鼠标Track
     end;
end;

end.
----------------------------------------------
我是个俗人
信息
登陆以后才能回复
Copyright © 2CCC.Com 盒子论坛 v3.0.1 版权所有 页面执行70.3125毫秒 RSS