How to detect when the mouse move away from a TPanel in Delphi ?

时间:2022-06-16 19:40:05

 using TrackMouseEvent to receive WM_MOUSELEAVE;

type
  TMyPanel = class(TPanel)
  private
    FMouseTracking: Boolean;
    FOnMouseLeave: TNotifyEvent;
    procedure WMMouseLeave(var Msg: TMessage); message WM_MOUSELEAVE;
  protected
    procedure MouseMove(Shift: TShiftState; X, Y: Integer); override;
  published
    property OnMouseLeave: TNotifyEvent read FOnMouseLeave write FOnMouseLeave;
  end;

procedure TMyPanel.MouseMove(Shift: TShiftState; X, Y: Integer);
var
  mEvnt: TTrackMouseEvent;
begin
  inherited;
  if not FMouseTracking then begin
    mEvnt.cbSize := SizeOf(mEvnt);
    mEvnt.dwFlags := TME_LEAVE;
    mEvnt.hwndTrack := Handle;
    TrackMouseEvent(mEvnt);
    FMouseTracking := True;
  end;
end;

procedure TMyPanel.WMMouseLeave(var Msg: TMessage);
begin
  Msg.Result := 0;
  FMouseTracking := False;
  if Assigned(FOnMouseLeave) then
    FOnMouseLeave(Self);
end;



////////////////////////////////////////////////////////////////////

3.If you don't have OnMouseEnter and OnMouseLeave then use OnMouseMove and capture the mouse to your panel. 
Capturing the mouse is slightly more work but the effects are better.


procedure Form1.Panel1MouseMove(Sender:TObject; Shift:TShiftState; X,Y:Integer);
begin
  if (X >= 0) and (Y >= 0) and (X < Panel1.Width) and (Y < Panel1.Height) then
    begin
      // Movement within the panel
      if GetCapture <> Panel1.Handle then
      begin
        // The mouse just moved over the panel. Do your "on enter" stuff
        // over here.
        SetCapture(Panel1.Handle); // Capture the mouse so we'll receive
                                   // mouse move messages even if the cursor
                                   // is no longer over our panel.
      end;
    end
  else
    begin
      // Movement outside the panel! This is possible because I've previously
      // captured the mouse.
      // Do your "move out" stuff over here.
      ReleaseCapture; // release mouse capture
    end;
end;

2.If you don't have OnMouseEnter and OnMouseLeave then use OnMouseMove and capture the mouse to your panel. Capturing the mouse is slightly more work but the effects are better.
1.But there is an (relatively) easy way to hook into other controls' message handling without actually subclassing them, by setting their WindowProc property. –  mghie Jul 5 '10 at 19:37

//////////////////////////////////////////////////////////////////////

To me work very well, I make a new bitbtn control derived from original bitbtn and implements the mouseenter and mouse leave, with Delphi 7. Follow my code:

TBitBtnPanel = class(TBitBtn)
  private
    { Private declarations }
    FOnMouseLeave: TNotifyEvent;
    FOnMouseEnter: TNotifyEvent;
    FActivateMouseLeave: boolean;
    procedure CMMouseEnter(var Msg: TMessage); message CM_MOUSEENTER;
    procedure CMMouseLeave(var Msg: TMessage); message CM_MOUSELEAVE;
  protected
    { Protected declarations }
  public
    { Public declarations }
    constructor Create(AOwner: TComponent); override;
  published
    { Published declarations }
    property OnMouseLeave: TNotifyEvent read FOnMouseLeave write FOnMouseLeave;
    property OnMouseEnter: TNotifyEvent read FOnMouseEnter write FOnMouseEnter;
  end;

{ TBitBtnPanel }

procedure TBitBtnPanel.CMMouseEnter(var Msg: TMessage);
begin
  Msg.Result := WM_CANCELMODE;
  FActivateMouseLeave:=True;
  if Assigned(FOnMouseEnter) then FOnMouseEnter(Self);
end;

procedure TBitBtnPanel.CMMouseLeave(var Msg: TMessage);
begin
  if (FActivateMouseLeave) then
  begin
    Msg.Result := WM_CANCELMODE;
    FActivateMouseLeave:=False;
    if Assigned(FOnMouseLeave) then FOnMouseLeave(Self);
  end;
end;

constructor TBitBtnPanel.Create(AOwner: TComponent);
begin
  FActivateMouseLeave:=True;
  inherited;
end;