2010-07-05 14 views
5

estoy usando el evento OnMouseMove para detectar cuando el puntero del ratón está sobre mi TPanel, ¿hay una manera de saber cuando el puntero del ratón se había alejado de ella?¿Cómo detectar cuando el mouse se aleja de un TPanel en Delphi 6?

necesito el panel de cambiar de color cuando el puntero del ratón está sobre ella y volver a su color original una vez que se alejó de él?

estoy usando Delphi 6 por cierto.

Por favor ayuda.

Atentamente.

Respuesta

6

Sin embargo, otra solución, utilizando TrackMouseEvent recibir 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; 
+0

Dado que la pregunta original no implica la creación de una clase descendiente TPanel probablemente una solución final es manejar WM_MOUSELEAVE en TPanel.WindowProc – kludg

+0

@Serg - Ok, pero su respuesta ya muestra cómo se hace :-). –

+0

Muchas gracias ... y muchas gracias a todos por las diferentes soluciones. – Snackmoore

8

Usted puede utilizar OnMouseEnter par de evento/OnMouseLeave para detectar ratón

procedure TForm1.Panel1MouseEnter(Sender: TObject); 
begin 
    Panel1.Caption:= 'IN'; 
    Panel1.Color:= clBlue; 
end; 

procedure TForm1.Panel1MouseLeave(Sender: TObject); 
begin 
    Panel1.Caption:= 'OUT'; 
    Panel1.Color:= clWhite; 
end; 

no puedo probar el siguiente código en Delphi 6, pero espero que está bien

Actualizado

Código de TrackMouseEvent agregado - gracias a Sertac Akyuz respuesta

unit Unit1; 

interface 

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

type 
    TForm1 = class(TForm) 
    Panel1: TPanel; 
    procedure FormCreate(Sender: TObject); 
    procedure FormDestroy(Sender: TObject); 
    procedure Panel1MouseMove(Sender: TObject; Shift: TShiftState; X, 
     Y: Integer); 
    private 
    { Private declarations } 
    FOldWndProc: TWndMethod; 
    FMouseInPanel: Boolean; 
    procedure PanelWndProc(var Message: TMessage); 
    public 
    { Public declarations } 
    end; 

var 
    Form1: TForm1; 

implementation 

{$R *.dfm} 

procedure TForm1.FormCreate(Sender: TObject); 
begin 
    FOldWndProc:= Panel1.WindowProc; 
    Panel1.WindowProc:= PanelWndProc; 
end; 

procedure TForm1.FormDestroy(Sender: TObject); 
begin 
    Panel1.WindowProc:= FOldWndProc; 
end; 

procedure TForm1.Panel1MouseMove(Sender: TObject; Shift: TShiftState; X, 
    Y: Integer); 
var 
    mEvnt: TTrackMouseEvent; 
begin 
    if not FMouseInPanel then begin 
    mEvnt.cbSize := SizeOf(mEvnt); 
    mEvnt.dwFlags := TME_LEAVE; 
    mEvnt.hwndTrack := Panel1.Handle; 
    TrackMouseEvent(mEvnt); 
    Panel1.Caption:= 'IN'; 
    FMouseInPanel:= True; 
    end; 
end; 

// if not defined in Delphi 6, WM_MOUSELEAVE = $02A3 
procedure TForm1.PanelWndProc(var Message: TMessage); 
begin 
    if Message.Msg = WM_MOUSELEAVE then begin 
    Panel1.Caption:= 'OUT'; 
    FMouseInPanel:= False; 
    end; 
    FOldWndProc(Message); 
end; 

end. 
+0

Espera chicos. .. Solo tengo OnMouseDown, OnMouseMove, OnMouseUp y no veo OnMouseEnter ni OnMouseLeave ni OnMouseOut ... Estoy usando Delphi 6 ... ¿no tengo suerte o hay otra forma? – Snackmoore

+0

Si no recuerdo mal, OnMouseEnter y OnMouseLeave no existían en Delphi 6. –

+2

AFAIK 'WM_MOUSELEAVE' no se publica si la ventana no está especificada en un' TrackMouseEvent'. –

2

OnMouseLeave. Tenga en cuenta que también necesita ver si el mouse dejó toda la aplicación, ya que he tenido OnMouseLeave no activado cuando el panel estaba en el borde del formulario y salí del formulario.

+0

+1 por mencionar "también debe ver si el mouse dejó toda la aplicación". –

3

Entonces, si usted no tiene OnMouseEnter y OnMouseLeave utilizar OnMouseMove y capturar el ratón para su panel. Capturar el mouse es un poco más de trabajo, pero los efectos son mejores.

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

Esto es bueno, pero también debe supervisar WM_CANCELMODE, que se envía si se captura el mouse y el foco se aleja. – mj2008

+0

@ mj2008, tiene razón, es solo que WM_CANCELMODE se envía a la ventana que anteriormente contenía la captura, por lo que se envía al Panel. A menos que el OP esté dispuesto a sub-clase TPanel, no hay una manera fácil de manejar WM_CANCELMODE. Sin embargo, debería haberlo mencionado. –

+1

Pero * existe * una forma (relativamente) fácil de engancharse en el manejo de mensajes de otros controles sin subclasificarlos, configurando su propiedad 'WindowProc'. – mghie

1

Crear su propio componente derivado de la TCustomPanel (o TPanel), ya que Delphi 6 no tiene los eventos MouseEnter y MouseLeave de forma predeterminada, se les puede añadir a sí mismo. Agregue esto a la sección privada de la sección de declaración:

procedure CMMouseEnter(var Message: TMessage); message CM_MOUSEENTER; 
procedure CMMouseLeave(var Message: TMessage); message CM_MOUSELEAVE; 

Después es todo sobre el manejo de la MouseEnter y eventos MouseLeave:

procedure TMyPanel.CMMouseEnter(var msg: TMessage); 
begin 
    inherited; 
    Color := clBlue; 
    { Do Whatever } 
end; 

procedure TMyPanel.CMMouseLeave(var msg: TMessage); 
begin 
    inherited; 
    Color := clRed; 
    { Do Whatever } 
end; 

Espero que esto ayude. Si el color no aparece agregar esto a su constructor de componentes:

ControlStyle := ControlStyle - [csParentBackground] + [csOpaque]; 
+0

El problema con los mensajes CM_MOUSE .. es que podrían no dispararse con movimientos rápidos del mouse, especialmente si un panel está cerca del borde de una forma, creo ... –

1

gracias por la ayuda. Me funcionan muy bien, hago un nuevo control bitbtn deriva de bitbtn original y implementa el MouseEnter licencia y el ratón, con Delphi 7. Siga mi código:

 
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; 

Hugo Barros - Brasil

Cuestiones relacionadas