Дельфы / Лазарь | Есть ли способ упростить глобальную обработку событий OnMouseEnter? - PullRequest
1 голос
/ 17 мая 2019

Проблема

Я хотел бы упростить следующий код в Delphi XE6 для Windows , который становится недоступным, так как я добавляю все больше и больше типов компонентов.

Примечание по переносимости: Я хотел бы использовать тот же код позже в Lazarus 2.0.2 для Linux без особых изменений, поэтому об обработке сообщений Windows не может быть и речи.

Проблема в том, что я не могу найти способ назначить обработчик события OnMouseEnter для всех компонентов во всей Форме.

Я попробовал все, что мог, включая различные классы, общие в их дереве объектов.,Кажется, что событие OnMouseEnter нигде не встречается.

Сам обработчик события содержит только одну команду (процедура = функция void), и его больше не будет, может быть, это могло бы упростить всю проблему?

Как вы можете видеть ниже, в этот момент мне нужно добавить каждый тип компонента (в настоящее время только 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;

Мотивация

Я программирую приложение color picker и поэтому хочу показать пользователю координаты мыши.

У меня есть таймер опроса, я неЯ не хочу добавлять больше кода, чем необходимо, поэтому я надеюсь, что это не требует пояснений:

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

Далее, у меня есть OnMouseLeave .

1 Ответ

6 голосов
/ 17 мая 2019

Кажется, что событие OnMouseEnter нигде не встречается.

На самом деле, это так.OnMouseEnter является членом TControl, от которого происходят все визуальные элементы управления, но большинство элементов управления не повышают его до published.Однако, поскольку он объявлен как 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 's защищенные члены, и блок, который объявляет TControlAccess, имеет доступ ко всем защищенным элементам TControlAccess.

С другой стороны, 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;
...