Как уведомить изменение между различными формами в Delphi?
Разработка на Delphi часто требует взаимодействия между разными пользовательскими интерфейсами, включая MDI (Multiple Document Interface) формы. Ситуации возникают, когда необходимо уведомлять другие открытые формы о каких-либо изменениях в одной из форм. Рассмотрим несколько подходов к решению этой задачи.
Использование собственных событий
Простейший способ – определить событие, которое передаёт необходимые данные об изменении. Форма, которая изменилась, производит вызов этого события, а форма, которой необходимо уведомление, реализует обработчик этого события. В методе OnCreate формы-инициатора можно назначить этот обработчик для формы-получателя.
type
TFormChangeEvent = procedure(Sender: TObject; const AData: string); of object;
procedure TForm1.Form1Create(Sender: TObject);
begin
// Предполагаем, что Form2 уже существует и мы хотим уведомить её об изменениях
TForm2(Form2Handle).OnFormChange := @Form1OnDataChanged;
end;
procedure TForm1.Form1NotifyChange(const AData: string);
begin
// Вызывается при изменении данных, например
OnFormChange(Sender, 'Изменённые данные');
end;
procedure TForm1.Form1OnDataChanged(Sender: TObject; const AData: string);
begin
// Обработка уведомления в Form2
end;
Применение паттерна "Наблюдатель" (Observer)
Этот шаблон проектирования позволяет объектам (называемым наблюдателями) подписываться на события объектов (называемых субъектами). Когда состояние субъекта изменяется, он автоматически уведомляет всех своих подписантов.
Пример использования паттерна в Delphi:
type
TObserver = interface(IInterface)
['{01234567-89AB-CDEF-0123-456789ABCDEF}']
procedure Update;
end;
TForm1 = class(TForm, TSubject)
private
FObservers: TList<TObserver>;
// Остальной код формы
protected
function GetObserverCount: Integer; virtual;
public
constructor Create(AOwner: TComponent); override;
destructor Destroy; override;
procedure Attach(AnObserver: TObserver);
procedure Detach(AnObserver: TObserver);
procedure NotifyObservers;
end;
TForm1 = class helper for TForm1
public
class function RegisterFormChangeSubject(aForm: TForm): Boolean; static; // Регистрация формы как субъекта для MDI
end;
constructor TForm1.Create(AOwner: TComponent);
begin
inherited Create(AOwner);
RegisterFormChangeSubject(Self);
end;
procedure TForm1.Attach(AnObserver: TObserver);
begin
FObservers := TList<TObserver>.Create(True);
try
FObservers.Add(AnObserver);
except
on E: Exception do
// Обработка исключений, если необходимо
end;
end;
procedure TForm1.Detach(AnObserver: TObserver);
var
ObserverList: TList<TObserver>;
begin
ObserverList := FObservers;
if ObserverList <> nil then
try
ObserverList.Remove(AnObserver);
finally
ObserverList.Free;
end;
end;
procedure TForm1.NotifyObservers;
var
Observer: TObserver;
begin
ObserverList := FObservers;
if ObserverList <> nil then
begin
for Observer in ObserverList do
Observer.Update;
end;
end;
TObserver = class helper for TForm2 // Предположим, что это другая форма
public
procedure Update; override;
end;
procedure TForm2.Update;
begin
// Действия при обновлении
end;
// При изменении данных вызываем метод уведомления наблюдателей
procedure TForm1.FormDataChanged;
begin
NotifyObservers;
end;
class function TForm1.RegisterFormChangeSubject(aForm: TForm): Boolean; static;
var
MdiClient: TMdiClient;
begin
Result := False;
if aForm is TMdiChild then
begin
with TMdiChild(aForm) do
begin
MdiClient := Owner as TMdiClient;
if Assigned(MdiClient) and (MdiClient.ActiveMDIChild = Self) then
if not MdiClient.OnMDIActivate then
MdiClient.OnMDIActivate := TNotifyEvent(@RegisterSubjects);
end;
end;
Result := True;
end;
// Процедура для регистрации субъектов в клиенте MDI при активации формы
procedure RegisterSubjects(Sender: TObject; var Active: Boolean);
var
MdiChild: TMdiChild;
begin
if not Active then
Exit;
for MdiChild in Sender.Components do
if (MdiChild is TMdiChild) and (not TForm1(MdiChild).IsSubjectRegistered) then
TForm1(MdiChild).RegisterAsSubject;
end;
Использование оконных сообщений
В Delphi можно использовать оконные сообщения для уведомления форм. Однако стоит помнить, что механизмы оконных сообщений в Windows, Linux и macOS различаются.
Пример использования оконного сообщения на Windows:
const
WM_FORM_CHANGED = WM_USER + 10;
procedure TForm1.FormDataChanged;
begin
// Предполагаем, что у нас есть форма Form2 с идентификатором окна Form2Handle
SendMessage(Form2Handle, WM_FORM_CHANGED, 0, 0);
end;
procedure TForm2.WMFormChanged(var Msg: TMessage);
begin
// Обработка сообщения о том, что данные в Form1 изменились
inherited;
end;
Для кроссплатформенных решений можно использовать специальные библиотеки или фреймворки, такие как LCLIntf и LMessages.
Выводы
Выбор метода зависит от конкретной задачи и требований проекта. Важно учитывать кросс-платформенность, если приложение должно работать на разных операционных системах. Паттерн "Наблюдатель" является универсальным решением, но может быть избыточным для простых задач. Оконные сообщения могут быть удобным способом взаимодействия между формами, но требуют более внимательного подхода при кросс-платформенной разработке.
Надеюсь, предоставленная информация поможет вам найти оптимальное решение для вашего проекта!
Вопрос касается методов уведомления различных форм в среде разработки Delphi о изменениях, происходящих в одной из форм, включая использование собственных событий, паттерна 'Наблюдатель' и оконных сообщений.
Комментарии и вопросы
Получайте свежие новости и обновления по Object Pascal, Delphi и Lazarus прямо в свой смартфон. Подпишитесь на наш Telegram-канал delphi_kansoftware и будьте в курсе последних тенденций в разработке под Linux, Windows, Android и iOS
Материалы статей собраны из открытых источников, владелец сайта не претендует на авторство. Там где авторство установить не удалось, материал подаётся без имени автора. В случае если Вы считаете, что Ваши права нарушены, пожалуйста, свяжитесь с владельцем сайта.