delphicomponentscontrolsmouseeventtimage

Delphi Custom TImage Component - MouseEnter, MouseLeave in component


I'm trying to build a component based on FMX.Objects.TImage. I want the permanently assigned images by MultiResBitmap.Items to change without having to use OnMouseEnter and OnMouseLeave in the application. Of course, I will use the constructor and the destructor.

I'm a beginner, and maybe I don't understand something. I've been trying for a week now, and I can't detect the mouse over the component and assign events correctly to it. I temporarily used ShowMessage() for the test.

Theoretically, this code should probably work and not work. Tell me what I'm doing wrong.

unit ImageCustoms;

interface

uses
  Winapi.Windows, Winapi.Messages, System.SysUtils, System.Classes, FMX.Types, vcl.Controls, FMX.Objects, FMX.ImgList, vcl.Dialogs, vcl.Graphics, FMX.ExtCtrls;

type
    TImageCostoms = class(TImage)
private
  { Private declarations }
    FOnMouseLeave: TNotifyEvent;
    FOnMouseEnter: TNotifyEvent;
    procedure CMMouseEnter(var msg: TMessage); message CM_MOUSEENTER;
    procedure CMMouseLeave(var msg: TMessage); message CM_MOUSELEAVE;
protected
  { Protected declarations }
    procedure DoMouseEnter; virtual;
    procedure DoMouseLeave; virtual;
public
  { Public declarations }
    //constructor Create(AOwner: TComponent); override;
    //destructor Destroy; override;
published
  { Published declarations }
    property OnMouseEnter: TNotifyEvent read FOnMouseEnter write FOnMouseEnter;
    property OnMouseLeave: TNotifyEvent read FOnMouseLeave write FOnMouseLeave;
end;

procedure Register;

implementation

procedure Register;
begin
  RegisterComponents('Samples', [TImageCostoms]);
end;

procedure TImageCostoms.CMMouseEnter(var msg: TMessage);
begin
  ShowMessage('Enter');
  DoMouseEnter;
end;

procedure TImageCostoms.CMMouseLeave(var msg: TMessage);
begin
  ShowMessage('Leave');
  DoMouseLeave;
end;

procedure TImageCostoms.DoMouseEnter;
begin
  if Assigned(FOnMouseEnter) then
  ShowMessage('Enter');
  FOnMouseEnter(Self);
end;

procedure TImageCostoms.DoMouseLeave;
begin
  if Assigned(FOnMouseLeave) then
  ShowMessage('Leave');
  FOnMouseLeave(Self);
end;

{constructor TImageCostoms.Create(AOwner: TComponent);
begin
  inherited Create(AOwner);
  MultiResBitmap.Items[0].Bitmap.LoadFromFile('focus0.png');    // .\img\i.png
end;

destructor TImageCostoms.Destroy;
begin
   inherited Destroy;
end; }

end.

Solution

  • First off, don't mix VCL and FMX units together in your own units. VCL and FMX are not designed to be used together. And since FMX is cross-platform, don't use Winapi units in your code unless you are writing Windows-specific code (which you are not, in this situation).

    You don't need to handle the CM_MOUSE(ENTER|LEAVE) messages directly, the framework already does that internally for you. And you don't need to redeclare the OnMouse(Enter|Leave) events, they already exist and are published in TImage.

    All you really need to do is override (not redeclare) the existing virtual DoMouse(Enter|Leave) methods from Timage, eg:

    unit ImageCustoms;
    
    interface
    
    uses
      System.SysUtils, System.Classes, FMX.Types, FMX.Objects, FMX.ImgList, FMX.ExtCtrls;
    
    type
      TImageCostoms = class(TImage)
      private
        { Private declarations }
      protected
        { Protected declarations }
        procedure DoMouseEnter; override;
        procedure DoMouseLeave; override;
      public
        { Public declarations }
        //constructor Create(AOwner: TComponent); override;
        //destructor Destroy; override;
      published
        { Published declarations }
      end;
    
    procedure Register;
    
    implementation
    
    procedure Register;
    begin
      RegisterComponents('Samples', [TImageCostoms]);
    end;
    
    procedure TImageCostoms.DoMouseEnter;
    begin
      ... 
      inherited;
    end;
    
    procedure TImageCostoms.DoMouseLeave;
    begin
      ...
      inherited;
    end;
    
    {constructor TImageCostoms.Create(AOwner: TComponent);
    begin
      inherited Create(AOwner);
      MultiResBitmap.Items[0].Bitmap.LoadFromFile('focus0.png');    // .\img\i.png
    end;
    
    destructor TImageCostoms.Destroy;
    begin
       inherited Destroy;
    end; }
    
    end.
    

    Don't use ShowMessage() to debug component code, especially in events that react to keyboard/mouse focus changes. If you want to see debug messages, use OutputDebugString() or equivilent instead, and then look for the messages in the IDE's Output window. Or, just make display changes in your UI, like color changes, etc.