Delphi 自定义 TImage 组件 - 组件中的 MouseEnter、MouseLeave

Posted

技术标签:

【中文标题】Delphi 自定义 TImage 组件 - 组件中的 MouseEnter、MouseLeave【英文标题】:Delphi Custom TImage Component - MouseEnter, MouseLeave in component 【发布时间】:2021-12-23 04:48:21 【问题描述】:

我正在尝试基于FMX.Objects.TImage 构建一个组件。我希望MultiResBitmap.Items 永久分配的图像可以更改,而不必在应用程序中使用OnMouseEnterOnMouseLeave。当然,我会使用构造函数和析构函数。

我是一个初学者,也许我不明白一些东西。我已经尝试了一周,但我无法检测到鼠标悬停在组件上并将事件正确分配给它。我暂时使用ShowMessage()进行测试。

理论上,这段代码应该可以工作,但不能工作。告诉我我做错了什么。

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.

【问题讨论】:

【参考方案1】:

谢谢你,它帮助了我,我正在努力上坡。事实上,在 FMX 中它很简单并且一切正常。非常感谢。我为程序编写了虚拟键盘支持,整个只是一个稍微改变焦点的透明按钮。再次感谢。对于后人,现在看起来像这样,我将尝试添加来自全局 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.```

【讨论】:

如果您想在某个 ImageList 中包含所有这些图像,那么为什么不直接使用 TSpeedButton 连接到 AnyImage 列表,然后简单地更改图像索引以显示所需图片。或者也许只是使用只有一张图像和附加效果的 SpeedButton 来达到您所说的这种轻微的焦点效果。通过这种方式,您可以减少应用程序所需的图像数量,并在聚焦状态和非聚焦状态之间逐渐过渡。这值得一试。【参考方案2】:

首先,不要在自己的设备中混合使用 VCL 和 FMX 设备。 VCL 和 FMX 不能一起使用。而且由于 FMX 是跨平台的,因此不要在代码中使用 Winapi 单位,除非您正在编写 Windows 特定 代码(在这种情况下您不是)。

您不需要直接处理CM_MOUSE(ENTER|LEAVE) 消息,框架已经在内部为您完成了这项工作。而且您不需要重新声明 OnMouse(Enter|Leave) 事件,它们已经存在并且在 TImage 中是 published

您真正需要做的只是override(而不是重新声明)来自Timage 的现有虚拟DoMouse(Enter|Leave) 方法,例如:

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.

不要使用ShowMessage() 调试组件代码,尤其是在对键盘/鼠标焦点更改做出反应的事件中。如果要查看调试消息,请改用OutputDebugString() 或等效项,然后在 IDE 的“输出”窗口中查找消息。或者,只需在 UI 中进行显示更改,例如颜色更改等。

【讨论】:

以上是关于Delphi 自定义 TImage 组件 - 组件中的 MouseEnter、MouseLeave的主要内容,如果未能解决你的问题,请参考以下文章

Delphi7Personal EAccessViolation 同时创建从 TImage 派生的组件

Delphi - 如何正确注册自 XE8 以来的图形类?

为 Delphi 制作可编辑的设计时组件

Delphi自定义组件如何在属性面板中实现打开文件的对话框?

Delphi 2009 - 在自定义 Delphi 组件中设置默认属性值

重新声明自定义 Delphi 组件的 Width 属性