views:

253

answers:

3

Hi,

I am making a custom Panel component which derives TPanel.

I want for my new component to have some code executed on the OnMouseEnter and OnMouseLeave events, however, i do not know how to implement it.

I see that TPanel has published properties OnMouseEnter, OnMouseLeave.

How do i override those and add some of my own code?

The example of my idea:
Default behaviour of TMyPanel which should be in component itself.

on event OnMouseEnter do: Color := NewColor;
on event OnMouseLeave do: Color := OldColor;

And then, i want to be able to assign some function to these events at run time. This assignment is done in the application.

.. TButton1.Click ..
begin
    MyPanel1.OnMouseEnter := DoSomethingMore;
    MyPanel1.OnMouseLeave := DoSomethingElse;
end;

so in the end, when mouse is over new panel, it should change color AND do some other actions written in DoSomethingMore procedure.

Thanks

+3  A: 

If they are available, you should override DoMouseEnter and DoMouseLeave. Otherwise, catch the corresponding messages, like the other answer demonstrates. Don't forget to call inherited, as this will call the events.

Uwe Raabe
This is a specific case of the general rule that when you're *writing* a component, the event properties are off-limits. Events are for *consumers* of the component, not the person *writing* the component. (When the writer and the consumer are the same person, it can get a little confusing.)
Rob Kennedy
Can i please get an extended answer?I get an error 'Method DoMouseEnter not found in base class' when i add this line to declarations'procedure DoMouseEnter; override;'I have tried OnMouseEnter instead of DoMouseEnter and i get same error.So i guess there is another way or am i doing something wrong?The base class is TPanel, and it has published properties:property OnMouseLeave;property OnMouseEnter;
You are right: the DoMouseEnter and DoMouseLeave are only available in the .NET version of Delphi. Besides that I count this as a fault in Delphi Win32, the way to go is to override CMMouseEnter and CMMouseLeave.
Uwe Raabe
You should edit your original answer. As this answer doesn't work.
Warren P
+8  A: 

Anoher approach is to handle the windows messages yourself:

type
  TMyPanel = class(TPanel)
  private
    procedure CMMouseEnter(var Message: TMessage); message CM_MOUSEENTER;
    procedure CMMouseLeave(var Message: TMessage); message CM_MOUSELEAVE;
  published
  end;

implementation

{ TMyPanel }

procedure TMyPanel.CMMouseEnter(var Message: TMessage);
begin
     // Do whatever your want before the event
     if Assigned(OnMouseEnter) then OnMouseEnter(Self);
end;

procedure TMyPanel.CMMouseLeave(var Message: TMessage);
begin
     // Do whatever your want before the event
     if Assigned(OnMouseLeave) then OnMouseLeave(Self);
end;

EDIT: See below for better VCL compliant version.

K.Sandell
This may be required, if TPanel has no DoMouseEnter method. The preferred way is to have the `cm_X` message handler call the virtual `DoX` method, and `DoX` calls the `OnX` event. Looks like CodeGear may have skipped the middle step.
Rob Kennedy
Thank you! This was just what i needed. It works perfectly.
You're handling CM_MOUSEENTER and CM_MOUSELEAVE messages and not calling inherited handlers. This breaks VCL functionality on TControl level. OnMouseEnter and OnMouseLeave will probably be called multiple times from child controls (you're not checking LParam). See TControl.CMMouseEnter for details.
TOndrej
You can invoke TControl.CMMOuseEnter and avoid breaking the VCL, from your function. K.Sandell. Please edit your code, add the "superclass invoke", TControl.CM... calls to your new versions.
Warren P
to call the inherited message handler, you can just add the following line: inherited;
TOndrej
A: 

Here's a VCL compliant version (tested D2010)

unit Unit1;

interface

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

type
  TMyPanel = class(TPanel)
  private
    procedure CMMouseEnter(var Message: TMessage); message CM_MOUSEENTER;
    procedure CMMouseLeave(var Message: TMessage); message CM_MOUSELEAVE;
  published
  end;

  TForm1 = class(TForm)
    Panel1: TPanel;
    procedure FormCreate(Sender: TObject);
  private
    { Private declarations }
  public
    { Public declarations }
    Procedure OnMEnter(Sender: TObject);
    Procedure OnMLeave(Sender: TObject);
  end;

var
  Form1: TForm1;

implementation

{$R *.dfm}

procedure TForm1.FormCreate(Sender: TObject);
begin
     With TMyPanel.Create(Form1) do
     Begin
          Parent := Form1;
          Caption := 'Test';
          OnMouseEnter := OnMEnter;
          OnMouseLeave := OnMLeave;
     End;
end;

procedure TForm1.OnMEnter(Sender: TObject);
begin
     Form1.Caption := 'Entered';
end;

procedure TForm1.OnMLeave(Sender: TObject);
begin
     Form1.Caption := 'Left';
end;

{ TMyPanel }

procedure TMyPanel.CMMouseEnter(var Message: TMessage);
begin
     // Do whatever your want before the event
     Self.Caption := 'Custom Enter';
     // Call inhertied method handler
     Inherited;
end;

procedure TMyPanel.CMMouseLeave(var Message: TMessage);
begin
     // Do whatever your want before the event
     Self.Caption := 'Custom Left';
     // Call inhertied method handler
     Inherited;
end;

end.
K.Sandell
Welcome to Stack Overflow. You really should have just edited your original answer since the only difference here is that you call `inherited`, which is exactly what the comments suggested should occur anyway.
Rob Kennedy
Thanx. Will edit in future cases!
K.Sandell