Home > Software engineering >  Delphi Custom TImage Component - MouseEnter, MouseLeave in component
Delphi Custom TImage Component - MouseEnter, MouseLeave in component

Time:11-11

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 onm ouseEnter: TNotifyEvent read FOnMouseEnter write FOnMouseEnter;
    property onm ouseLeave: 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.

CodePudding user response:

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.

CodePudding user response:

Thank you, it helped me, I was trying very uphill. In fact, in FMX it is simple and everything works. Thank you very much. I write the virtual keyboard support for the program, the whole is just a transparent button changing the focus slightly. Thanks again. For posterity, for now, it looks like this, I will try to add support from the global ImageList.


interface
uses
 System.SysUtils, System.Classes, FMX.Types, FMX.Objects, FMX.ImgList, vcl.Dialogs, System.UITypes;
type
    TImageCostoms = class(TImage)

private
  { Private declarations }
    procedure DoMouseEnter; override;
    procedure DoMouseLeave; override;

protected
  { Protected declarations }

public
  { Public declarations }
    constructor Create(AOwner: TComponent); override;

published
  { Published declarations }

end;

procedure Register;

implementation


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

procedure TImageCostoms.DoMouseEnter;
begin
  inherited ;
  MultiResBitmap.Items[1].Bitmap.LoadFromFile('focus1.png');
end;

procedure TImageCostoms.DoMouseLeave;
begin
  inherited;
  MultiResBitmap.Items[0].Bitmap.LoadFromFile('focus0.png');
end;

constructor TImageCostoms.Create(AOwner: TComponent);
begin
  inherited Create(AOwner);
  width:=45;
  height:=45;
  MultiResBitmap.Items[0].Bitmap.LoadFromFile('focus0.png');
end;


end.```
  • Related