Разработчики, работающие с Delphi, часто сталкиваются с необходимостью упрощения и универсализации кода для повышения его поддерживаемости и упрощения процесса портирования приложений на другие платформы. В данной статье мы рассмотрим, как можно упростить обработку событий в Delphi XE6, с целью последующего использования того же кода в Lazarus, что позволит избежать специфики Windows-сообщений.
Проблема
Разработчик столкнулся с проблемой усложнения кода при добавлении новых типов компонентов в проект на Delphi XE6. Необходимо было найти способ назначения обработчика события OnMouseEnter для всех компонентов на форме, что позволило бы избежать необходимости добавления каждого типа компонента в цикл. Кроме того, важным условием является возможность использования того же кода в Lazarus 2.0.2 на Linux, что исключает использование Windows-сообщений.
Решение
На самом деле, обработчик события OnMouseEnter доступен для всех визуальных компонентов, так как является членом класса TControl, от которого наследуются все визуальные компоненты. Однако большинство компонентов не публикуют это событие. Тем не менее, можно использовать доступный класс для доступа к защищённым членам TControl, что позволит назначить обработчик события всем компонентам, не зависимо от их типа. Пример такого класса и процедуры назначения обработчика приведён ниже:
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;
Другой способ - использование 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, использует RTTI для получения информации о типе свойства и его видимости:
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;
Prop := Ctx.GetType(Comp.ClassType).GetProperty('OnMouseEnter');
if (Prop <> nil) and (Prop.Visibility in [TMemberVisibility.mvPublic, TMemberVisibility.mvPublished]) then
Prop.SetValue(Comp, V);
end;
end;
Заключение
В данной статье были рассмотрены подходы к универсализации обработчиков событий в Delphi, что позволяет значительно упростить код и облегчить его поддержку и переносимость. Приведённые примеры кода могут быть использованы в проектах, где требуется назначение единого обработчика для различных типов компонентов, что особенно актуально при портировании приложений на другие платформы, такие как Lazarus для Linux.
Улучшение поддержки кода в Delphi XE6 для упрощения портирования в Lazarus путем создания универсальных обработчиков событий.
Комментарии и вопросы
Получайте свежие новости и обновления по Object Pascal, Delphi и Lazarus прямо в свой смартфон. Подпишитесь на наш Telegram-канал delphi_kansoftware и будьте в курсе последних тенденций в разработке под Linux, Windows, Android и iOS