Delphi 如何使我的组件检测鼠标位置?

Delphi 如何使我的组件检测鼠标位置?,delphi,delphi-2010,Delphi,Delphi 2010,我想写一个小组件,告诉我鼠标当前在哪个控件上。 当它发现choosen控件时,它应该触发消息(例如) 但是我不知道我应该怎么做才能一直得到鼠标的位置。 这就是我得到的: TMouseOverControl = class(TComponent) private fActive: Boolean; fControl: TWinControl; public constructor Create(AOwner: TComponent); override;

我想写一个小组件,告诉我鼠标当前在哪个控件上。 当它发现choosen控件时,它应该触发消息(例如)

但是我不知道我应该怎么做才能一直得到鼠标的位置。 这就是我得到的:

  TMouseOverControl = class(TComponent)
  private
    fActive: Boolean;
    fControl: TWinControl;
  public
    constructor Create(AOwner: TComponent); override;
    procedure Loaded; override;
    procedure SpotIt;
  published
    property Active: Boolean read fActive write fActive;
    property Control: TWinControl read fControl write fControl; // when mouse is over this control show me the message
  end;

constructor TMouseOverControl.Create(AOwner: TComponent);
begin
  // nothing interesting here
  // don't have control property here - so overrided the loaded method
  inherited;
end;

procedure TMouseOverControl.Loaded;
begin
  inherited;

  //  TForm(Owner).Mo.... := SpotIt.... 
  //  what should i do to make it work?
 end;

 procedure TMouseOverControl.SpotIt;
 begin
// IsMouseOverControl is easy to implement
// http://delphi.about.com/od/delphitips2010/qt/is-some-delphi-tcontrol-under-the-mouse.htm
       if IsMouseOverControl(Control) then 
         ShowMessage('Yep, U got it!');
     end;

有什么想法吗?

你只需要在鼠标移动时检查/更新。因此,您可以使用
TApplicationEvents
跟踪
WM\u MOUSEMOVE
消息

// Edit: these variables are intended to be private fields of the component class
var
  FAppEvents: TApplicationEvents;
  FFoundControl: Boolean;
  FCurrentControl: TWinControl;

procedure TMyComponent.HandleAppMessage(var Msg: tagMSG; var Handled: Boolean);
var
  Control: TWinControl;
begin
  if (Msg.message = WM_MOUSEMOVE) and not FFoundControl then
  begin
    Control:= FindControl(Msg.hwnd);
    if Assigned(Control) then
    begin
      FCurrentControl:= Control;
      FFoundControl:= True;
    end;
  end else
  if (Msg.message = WM_MOUSELEAVE) then
    FFoundControl:= False;
end;

procedure TMyComponent.FormCreate(Sender: TObject);
begin
  FAppEvents:= TApplicationEvents.Create(nil);
  FAppEvents.OnMessage:= HandleAppMessage;
end;
这当然可以进行优化,例如,还可以检查WM_MOUSELEAVE,这样您就不必在每次鼠标移动时都
FindControl
。此解决方案适用于
TWinControls
及其子体


编辑:使用WM_MOUSELEAVE。

您只需在鼠标移动时进行检查/更新。因此,您可以使用
TApplicationEvents
跟踪
WM\u MOUSEMOVE
消息

// Edit: these variables are intended to be private fields of the component class
var
  FAppEvents: TApplicationEvents;
  FFoundControl: Boolean;
  FCurrentControl: TWinControl;

procedure TMyComponent.HandleAppMessage(var Msg: tagMSG; var Handled: Boolean);
var
  Control: TWinControl;
begin
  if (Msg.message = WM_MOUSEMOVE) and not FFoundControl then
  begin
    Control:= FindControl(Msg.hwnd);
    if Assigned(Control) then
    begin
      FCurrentControl:= Control;
      FFoundControl:= True;
    end;
  end else
  if (Msg.message = WM_MOUSELEAVE) then
    FFoundControl:= False;
end;

procedure TMyComponent.FormCreate(Sender: TObject);
begin
  FAppEvents:= TApplicationEvents.Create(nil);
  FAppEvents.OnMessage:= HandleAppMessage;
end;
这当然可以进行优化,例如,还可以检查WM_MOUSELEAVE,这样您就不必在每次鼠标移动时都
FindControl
。此解决方案适用于
TWinControls
及其子体


编辑:使用WM_MOUSELEAVE。

像这样的东西怎么样:

// rectangle where you are interested to check if the mouse is into..
targetRect := Rect(0, 0, ImageZoom.Width, ImageZoom.Height);

// find out where the mouse is..
mousePosition := Point(0, 0);
GetCursorPos(mousePosition);

// find out if the point.. from screen to client.. is inside that rectangle
isMouseInside := (PtInRect(targetRect, ScreenToClient(mousePosition)));

像这样的怎么样:

// rectangle where you are interested to check if the mouse is into..
targetRect := Rect(0, 0, ImageZoom.Width, ImageZoom.Height);

// find out where the mouse is..
mousePosition := Point(0, 0);
GetCursorPos(mousePosition);

// find out if the point.. from screen to client.. is inside that rectangle
isMouseInside := (PtInRect(targetRect, ScreenToClient(mousePosition)));

Application.OnIdle事件不是如您的?@NGLN所示工作吗?所以我应该用我自己的事件覆盖它?啊,对不起,您当然希望它成为您组件的一部分。Duh…你可以使用计时器、鼠标簿或控件的子类(因为它是TWinControl)。@NGLN控件只是为了让它更容易阅读。我收集了一些控件。MouseHook看起来有点复杂,但是计时器可以完成它的工作。OnIdle事件可以像你的?@NGLN演示的那样工作,所以我应该用我自己的事件覆盖它?啊,对不起,你当然希望它成为你组件的一部分。Duh…你可以使用计时器、鼠标簿或控件的子类(因为它是TWinControl)。@NGLN控件只是为了让它更容易阅读。我收集了一些控件。MouseHook看起来有点复杂,但计时器可以完成它的工作+1应用程序事件不像singleton。我完全忘记了。虽然我认为AppEvents.OnIdle中的
PtInRect
解决方案更好。另外,变量应该是私有字段。@NGLN我只是太懒了,不能编写组件类。这些变量不是用来作为全局变量的。我添加了一条评论。+1 TApplicationEvents与singleton不同。我完全忘记了。虽然我认为AppEvents.OnIdle中的
PtInRect
解决方案更好。另外,变量应该是私有字段。@NGLN我只是太懒了,不能编写组件类。这些变量不是用来作为全局变量的。我补充了一条评论。