При разработке приложений на Delphi часто возникает необходимость блокировки одновременной обработки событий, особенно когда запускается длительная задача, и пользователь не должен иметь возможность инициировать новые события до её завершения. Рассмотрим несколько подходов к решению этой задачи.
Стандартный подход с использованием флага fRunning
Один из распространённых способов - использование булевой переменной fRunning, которая указывает, выполняется ли в данный момент обработчик события. Пример кода:
procedure TFormFoo.Button_Click(Sender: TObject);
begin
if not fRunning then
try
fRunning := true;
if (Sender = Button1) then // Вызов медленной задачи ...
if (Sender = Button2) then // Вызов другой задачи ...
if (Sender = Button3) then // Вызов ещё одной задачи ...
finally
fRunning := false;
end;
end;
Блокировка на уровне формы
Можно временно отключить всю форму, чтобы предотвратить обработку событий:
procedure TFormFoo.Button_Click(Sender: TObject);
begin
try
Enabled := False;
// Выполнение длительной задачи
finally
Enabled := True;
end;
end;
Использование TAction и события OnUpdate
Можно связать обработку нажатий кнопок с действиями (actions) и управлять их доступностью через событие OnUpdate:
procedure TForm1.acButtonUpdate(Sender: TObject);
begin
(Sender as TAction).Enabled := not fRunning;
end;
Отключение обработчика события
Ещё один способ - временно назначить обработчик события nil, что предотвратит его повторное выполнение:
procedure TForm1.Button1Click(Sender: TObject);
var
OldHandler: TNotifyEvent;
begin
OldHandler := (Sender as TButton).OnClick;
(Sender as TButton).OnClick := nil;
try
// Выполнение длительной задачи
finally
(Sender as TButton).OnClick := OldHandler;
end;
end;
Для удобства можно создать интерфейс, который обёртывает эту логику:
type
TTempUnassignOnClick = class(TInterfacedObject, IInterface)
private
FOldEvent: TNotifyEvent;
FBtn: TButton;
public
constructor Create(_Btn: TButton);
destructor Destroy; override;
end;
constructor TTempUnassignOnClick.Create(_Btn: TButton);
begin
inherited Create;
FBtn := _Btn;
FOldEvent := FBtn.OnClick;
FBtn.OnClick := NIL;
end;
destructor TTempUnassignOnClick.Destroy;
begin
FBtn.OnClick := FOldEvent;
inherited;
end;
function TempUnassignOnClick(_Btn: TButton): IInterface;
begin
Result := TTempUnassignOnClick.Create(_Btn);
end;
Заключение
В зависимости от конкретной задачи и требований к приложению, можно выбрать наиболее подходящий способ управления событиями. Важно помнить, что все события в VCL обрабатываются в главном потоке, и одновременное выполнение нескольких событий невозможно, пока не завершится текущий обработчик события. Однако, если длительная задача выполняется в отдельном потоке, необходимо убедиться, что пользовательский интерфейс остаётся отзывчивым, и для этого могут потребоваться дополнительные меры, такие как временное отключение кнопок или использование Application.ProcessMessages.
Управление событиями в Delphi может потребовать блокировки одновременной обработки для предотвращения запуска новых событий во время выполнения длительных задач.
Комментарии и вопросы
Получайте свежие новости и обновления по Object Pascal, Delphi и Lazarus прямо в свой смартфон. Подпишитесь на наш Telegram-канал delphi_kansoftware и будьте в курсе последних тенденций в разработке под Linux, Windows, Android и iOS
Материалы статей собраны из открытых источников, владелец сайта не претендует на авторство. Там где авторство установить не удалось, материал подаётся без имени автора. В случае если Вы считаете, что Ваши права нарушены, пожалуйста, свяжитесь с владельцем сайта.