Разработчики, работающие с Delphi 10.4 FMX, могут столкнуться с проблемой обновления элементов интерфейса пользователя, таких как метки, в многопоточных приложениях. В частности, использование метода Application.ProcessMessages() может быть неэффективным или несовместимым с многопоточностью, что приводит к необходимости поиска альтернативных решений.
Проблема
При работе с многопоточными приложениями в Delphi 10.4 FMX, разработчики сталкиваются с необходимостью обновлять элементы пользовательского интерфейса, не блокируя основной поток выполнения. Примером такой задачи может служить обновление текста метки в течение определенного времени.
Контекст
В статье рассматривается пример простой программы на Delphi 10.4 FMX, где необходимо обновить метку трижды с задержкой между обновлениями. Автор использует подход с многопоточностью, следуя рекомендациям из различных источников, но сталкивается с проблемой, что обновление метки происходит некорректно при использовании нескольких уровней изменений.
Решение
Для начала, стоит упомянуть, что функция Measure1sec, используемая в примере, может быть неэффективной. Вместо использования TStopWatch в цикле, лучше использовать TThread.Sleep. Это упрощает код и делает его более читаемым.
procedure Measure1sec(wait: integer); inline;
begin
TThread.Sleep(wait);
end;
Однако, если задача состоит в задержке, то вызов Measure1sec можно и вовсе исключить, заменив его на прямую задержку с помощью TThread.Sleep.
Основная проблема в том, что рабочий поток выполняет обновление метки всего один раз. Для выполнения нескольких обновлений, необходимо, чтобы в рабочем потоке были реализованы соответствующие действия.
procedure TForm1.Button1Click(Sender: TObject);
begin
TThread.CreateAnonymousThread(
procedure
begin
TThread.Synchronize(nil,
procedure
begin
label1.Text := 'apple';
end
);
TThread.Sleep(500);
TThread.Synchronize(nil,
procedure
begin
label1.Text := 'orange';
end
);
TThread.Sleep(500);
TThread.Synchronize(nil,
procedure
begin
label1.Text := 'done';
end
);
TThread.Sleep(500);
end
).Start;
end;
Однако, использование многопоточности в данном случае не является оптимальным, так как большая часть работы все равно выполняется в основном потоке пользовательского интерфейса. В качестве альтернативы можно использовать TThread.ForceQueue, который позволяет выполнить процедуру в основном потоке через заданный интервал времени.
procedure TForm1.Button1Click(Sender: TObject);
begin
Step1;
end;
procedure TForm1.Step1;
begin
label1.Text := 'apple';
TThread.ForceQueue(nil, Step2, 500);
end;
procedure TForm1.Step2;
begin
label1.Text := 'orange';
TThread.ForceQueue(nil, Step3, 500);
end;
procedure TForm1.Step3;
begin
label1.Text := 'done';
end;
Или более кратко:
procedure TForm1.Button1Click(Sender: TObject);
begin
label1.Text := 'apple';
TThread.ForceQueue(nil,
procedure
begin
label1.Text := 'orange';
end,
500
);
TThread.ForceQueue(nil,
procedure
begin
label1.Text := 'done';
end,
1000
);
end;
Заключение
При работе с многопоточными приложениями Delphi 10.4 FMX важно понимать, когда и как следует использовать многопоточность, а когда достаточно выполнить операции в основном потоке с помощью TThread.ForceQueue. Это позволит избежать ненужной нагрузки на систему и обеспечить корректное обновление элементов пользовательского интерфейса.
Разработчики столкнулись с проблемой обновления элементов пользовательского интерфейса, таких как метки, в многопоточных приложениях на Delphi 10.4 FMX, что требует поиска эффективных решений для асинхронного обновления без блокировки основного потока.
Комментарии и вопросы
Получайте свежие новости и обновления по Object Pascal, Delphi и Lazarus прямо в свой смартфон. Подпишитесь на наш Telegram-канал delphi_kansoftware и будьте в курсе последних тенденций в разработке под Linux, Windows, Android и iOS