德尔福/拉撒路|有没有办法简化全局 OnMouseEnter 事件处理?

标签 delphi event-handling portability lazarus simplify

问题

我想在Windows 上的Delphi XE6中简化以下代码,随着我添加越来越多类型的组件,该代码变得难以维护。

可移植性说明:我想稍后在 Linux 上的 Lazarus 2.0.2 中使用相同的代码,几乎不需要任何更改,因此 Windows 消息处理不再适用问题。

问题是,我似乎找不到一种方法将 OnMouseEnter 事件处理程序分配给整个表单上的所有组件。

我尽了一切努力,包括对象树中常见的各种类。 OnMouseEnter 事件似乎没有任何共同点。

事件处理程序本身只包含一个命令(procedure = void function),并且不会再有更多命令,也许这可以简化整个问题?

如下所示,此时我需要将每种类型的组件(目前只有 TLabel、TButton 和 TEdit)添加到 for 循环中。

<小时/>
procedure TFormMain.FormCreate(Sender: TObject);
var
    I: Integer;
begin
    for I := 0 to FormMain.ComponentCount - 1 do
    begin
        if FormMain.Components[I] is TLabel then
        begin
            (FormMain.Components[I] as TLabel).OnMouseEnter
                := @CustomGenericMouseEnter;
        end;
        if FormMain.Components[I] is TButton then
        begin
            (FormMain.Components[I] as TButton).OnMouseEnter
                := @CustomGenericMouseEnter;
        end;
        if FormMain.Components[I] is TEdit then
        begin
            (FormMain.Components[I] as TEdit).OnMouseEnter
                := @CustomGenericMouseEnter;
        end;
    end;
end;

procedure TFormMain.CustomGenericMouseEnter(Sender: TObject);
begin
    SingleCustomProcedure; // no arguments, nor return value
end;
<小时/>

动机

我正在编写一个颜色选择器应用程序,因此想向用户显示鼠标坐标。

我在那里有一个轮询计时器,我不想添加不必要的代码,所以我希望这是不言自明的:

procedure TFormMain.TimerMousePollTimer(Sender: TObject);
begin
    if MousePosChanged then
    begin
        LabelEdit_MousePosX.Text := MousePosX.ToString;
        LabelEdit_MousePosY.Text := MousePosY.ToString;
    end;
end;

此外,我确实实现了 OnMouseLeave

最佳答案

The OnMouseEnter event seems to be nowhere in the common ground.

事实上,确实如此。 OnMouseEnterTControl 的成员,所有可视控件均源自该控件,但大多数控件不会将其提升为已发布。但是,由于它被声明为 protected ,因此您可以使用访问器类在任何控件上访问它,例如:

type
  TControlAccess = class(TControl)
  end;

procedure TFormMain.FormCreate(Sender: TObject);
var
  I: Integer;
  Comp: TComponent;
begin
  for I := 0 to ComponentCount - 1 do
  begin
    Comp := Components[I];
    if Comp is TControl then
      TControlAccess(Comp).OnMouseEnter := CustomGenericMouseEnter;
  end;
end;

这是有效的,因为 TControlAccess 可以访问所有 TControl 的 protected 成员,并且声明 TControlAccess 的单元可以访问所有TControlAccess 的 protected 成员。

另一方面,OnMouseEnter 最初是 protected ,因此控件可以决定是否要公开对其的访问。如果您想尊重该决定并仅将其设置为促进该决定的控件,则可以使用 RTTI,例如:

uses
  ..., TypInfo;

procedure TFormMain.FormCreate(Sender: TObject);
var
  I: Integer;
  Comp: TComponent;
  Prop: PPropInfo;
  M: TMethod;
begin
  TNotifyEvent(M) := CustomGenericMouseEnter;
  for I := 0 to ComponentCount - 1 do
  begin
    Comp := Components[I];
    if not (Comp is TControl) then Continue;
    Prop := GetPropInfo(Comp, 'OnMouseEnter', [tkMethod]);
    if Prop <> nil then
      SetMethodProp(Comp, Prop, M);
  end;
end;

或者(仅限 Delphi 2010+):

uses
  ..., System.Rtti;

procedure TFormMain.FormCreate(Sender: TObject);
var
  I: Integer;
  Ctx: TRttiContext;
  Comp: TComponent;
  Prop: TRttiProperty;
  V: TValue;
begin
  V := TValue.From<TNotifyEvent>(CustomGenericMouseEnter);
  for I := 0 to ComponentCount - 1 do
  begin
    Comp := Components[I];
    if not (Comp is TControl) then Continue;
    Ctx.GetType(Comp.ClassType).GetProperty('OnMouseEnter');
    if (Prop <> nil) and (Prop.Visibility in [TMemberVisibility.mvPublic, TMemberVisibility.mvPublished]) then
      Prop.SetValue(Comp, V);
  end;
end;

关于德尔福/拉撒路|有没有办法简化全局 OnMouseEnter 事件处理?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/56179235/

相关文章:

javascript - 非附加 Image.onload 垃圾回收

javascript - Gatsbyjs + Google Analytics - 跟踪自定义事件?

Angular - 根据变量变化触发事件

sql - 有诸如可移植SQL之类的东西吗?

delphi - 改善旧系统(尤其是笔记本电脑(Delphi 6))上的Indy HTTP客户端性能?

delphi - 当掩码包含 "["时,如何使用 TMask ?

delphi - 使用外键时创建表语句中的语法错误

delphi - 验证真实日期

c - 如何检查我是否可以使用 <sys/statvfs.h>?

c++ - 判断 C++ 代码是否可移植