Карта сайта Kansoftware
НОВОСТИУСЛУГИРЕШЕНИЯКОНТАКТЫ
KANSoftWare

Решение проблемы блокировки UI при работе с потоками в Delphi

Delphi , Интернет и Сети , FTP

IdThreadComponent и блокировка пользовательского интерфейса в Delphi

При работе с потоками в Delphi, важно учитывать, что потоки выполняются параллельно с основным потоком пользовательского интерфейса (UI). Если не соблюдать осторожность, это может привести к блокировке UI и ухудшению пользовательского опыта. В этой статье мы рассмотрим проблему, когда использование IdThreadComponent блокирует UI после завершения загрузки файла и отправки HTTP POST-запроса.

Проблема

Разработчик использует IdThreadComponent для выполнения простой загрузки файла на FTP-сервер. После завершения загрузки файла отправляется HTTP POST-запрос на сервер, и в зависимости от ответа сервера отображается соответствующее сообщение. После отображения сообщения, приложение блокируется, и пользователь больше не может взаимодействовать с его controls.

Причина проблемы

Проблема заключается в том, что все операции с UI выполняются в основном потоке UI. Когда IdThreadComponent завершает свою работу, событие OnWorkEnd вызывается в том же потоке, что и TIdFTP, а не в основном потоке UI. Attempting to update UI controls or display messages from this non-UI thread results in the UI becoming unresponsive.

Решение проблемы

Чтобы решить эту проблему, необходимо синхронизировать доступ к UI из неглавного потока. Можно использовать TThread.Queue или TIdNotify для этого. Ниже приведены примеры кода, демонстрирующие оба подхода.

  1. Использование TThread.Queue
procedure TfrmNoticeWindow.IdThreadComponent1Run(Sender: TIdCustomThreadComponent);
begin
  IdFtp1.Host := 'ip';
  IdFtp1.Username := 'user';
  IdFtp1.Password := 'pass';
  if aborted then Exit;
  try
    IdFtp1.Connect;
  except
    TThread.Queue(nil,
      procedure
      begin
        msgDlgBox.MessageDlg('Could not connect!', mtError, [mbOk], 0);
      end
    );
    Exit;
  end;
  try
    if not aborted then
      IdFtp1.Put(txtPath.text, file_name);
  finally
    IdFtp1.Disconnect;
  end;
end;

procedure TfrmNoticeWindow.IdThreadComponent1AfterRun(Sender: TIdCustomThreadComponent);
begin
  publishing := false;
  TThread.Queue(nil,
    procedure
    begin
      uploadGauge.Value := 0;
      uploadGauge.Visible := false;
      frmNoticeWindow.Height := 512;
      btnUpload.Caption := 'Publish';
      if not aborted then
      begin
        txtPath.Text := '';
        txtNoticeHeader.Text := '';
      end;
    end
  );
end;

procedure TfrmNoticeWindow.IdFTP1Work(Sender: TObject; AWorkMode: TWorkMode; AWorkCount: Int64);
begin
  if aborted then
    IdFtp1.Abort;
end;

procedure TfrmNoticeWindow.IdFTP1WorkEnd(Sender: TObject; AWorkMode: TWorkMode);
var
  Params : TStringList;
  Resp : String;
begin
  if aborted then Exit;
  Params := TStringList.Create;
  try
    Params.Add('enotice_publish='+packet);
    Resp := doPost('url', params);
  finally
    Params.Free;
  end;
  TThread.Queue(nil,
    procedure
    begin
      if (Resp = 'Notice published successfully!') then
        msgDlgBox.MessageDlg(Resp, mtInformation, [mbOk], 0)
      else
        msgDlgBox.MessageDlg(Resp, mtError, [mbOk], 0);
    end
  );
end;
  1. Использование TIdNotify
uses
  ..., IdSync;

procedure TfrmNoticeWindow.MsgBoxCouldNotConnect;
begin
  msgDlgBox.MessageDlg('Could not connect!', mtError, [mbOk], 0);
end;

procedure TfrmNoticeWindow.MsgBoxPostOk;
begin
  msgDlgBox.MessageDlg('Notice published successfully!', mtInformation, [mbOk], 0)
end;

procedure TfrmNoticeWindow.MsgBoxPostFail;
begin
  msgDlgBox.MessageDlg('Notice failed to publish!', mtError, [mbOk], 0);
end;

procedure TfrmNoticeWindow.ResetUiOk;
begin
  uploadGauge.Value := 0;
  uploadGauge.Visible := false;
  frmNoticeWindow.Height := 512;
  btnUpload.Caption := 'Publish';
  txtPath.Text := '';
  txtNoticeHeader.Text := '';
end;

procedure TfrmNoticeWindow.ResetUiAborted;
begin
  uploadGauge.Value := 0;
  uploadGauge.Visible := false;
  frmNoticeWindow.Height := 512;
  btnUpload.Caption := 'Publish';
end;

// Остальной код аналогичен первому примеру, но с использованием TIdNotify вместо TThread.Queue

Обе реализации решают проблему блокировки UI, синхронизируя доступ к UI из неглавного потока с помощью TThread.Queue или TIdNotify. Это гарантирует, что все операции с UI выполняются в основном потоке UI, что предотвращает блокировку и обеспечивает плавную работу приложения.

Создано по материалам из источника по ссылке.

В данном контексте описывается проблема блокировки пользовательского интерфейса в приложении, созданном на Delphi, которая возникает при использовании `IdThreadComponent` для загрузки файла на FTP-сервер и отправки HTTP POST-запроса после завершения загру


Комментарии и вопросы

Получайте свежие новости и обновления по Object Pascal, Delphi и Lazarus прямо в свой смартфон. Подпишитесь на наш Telegram-канал delphi_kansoftware и будьте в курсе последних тенденций в разработке под Linux, Windows, Android и iOS




Материалы статей собраны из открытых источников, владелец сайта не претендует на авторство. Там где авторство установить не удалось, материал подаётся без имени автора. В случае если Вы считаете, что Ваши права нарушены, пожалуйста, свяжитесь с владельцем сайта.


:: Главная :: FTP ::


реклама


©KANSoftWare (разработка программного обеспечения, создание программ, создание интерактивных сайтов), 2007
Top.Mail.Ru

Время компиляции файла: 2024-12-22 20:14:06
2025-06-16 16:07:11/0.0032880306243896/0