IdThreadComponent 弄乱了用户界面
IdThreadComponent messes the User interface
我正在使用 IdThreadComponent 执行简单的 ftp 上传到服务器。
ftp上传的代码如下:
procedure TfrmNoticeWindow.IdThreadComponent1Run(
Sender: TIdCustomThreadComponent);
begin
IdFtp1.Host := 'ip';
IdFtp1.Username := 'user';
IdFtp1.Password := 'pass';
try
IdFtp1.Connect;
except
begin
msgDlgBox.MessageDlg('Could not connect!', mtError, [mbOk], 0);
publishing := false;
end;
end;
IdFtp1.Put(txtPath.text, file_name);
IdFtp1.Quit;
IdFtp1.Disconnect;
End;
FtpWorkEnd 如下:
procedure TfrmNoticeWindow.IdFTP1WorkEnd(Sender: TObject;
AWorkMode: TWorkMode);
var
Params : TStringList;
Resp : String;
begin
IdThreadComponent1.Active := false;
Params := TStringList.Create;
Params.Add('enotice_publish='+packet);
if (aborted = true) then
begin
IdFtp1.Quit;
idFtp1.Disconnect;
aborted := false;
uploadGauge.Value := 0;
uploadGauge.Visible := false;
frmNoticeWindow.Height := 512;
btnUpload.Caption := 'Publish';
exit;
end;
Resp := doPost('url', params);
if (Resp = 'Notice published successfully!') then
msgDlgBox.MessageDlg(Resp, mtInformation, [mbOk], 0)
else
msgDlgBox.MessageDlg(Resp, mtError, [mbOk], 0);
frmNoticeWindow.Refresh;
uploadGauge.Value := 0;
uploadGauge.Visible := false;
frmNoticeWindow.Height := 512;
btnUpload.Caption := 'Publish';
publishing := false;
txtPath.Text := '';
txtNoticeHeader.Text := '';
end;
上传完成后,生成 http post 作为响应,我从服务器得到一个字符串 [Success/Failure]。
问题是,在这个 MessageDlg 之后,我的应用程序的组件变成了白色块,应用程序的控件无法再使用。
我确实在表单上尝试了 update(),但没有帮助。
我正在使用 Business Skin Forms 为我的应用程序设计皮肤,线程组件在关闭后弄乱了表单。
TIdThreadComponent.OnRun
事件处理程序在工作线程的上下文中运行,而不是在主 UI 线程中运行。您的所有 TIdFTP
操作在工作线程的上下文中都是 运行,这很好。但是,您的 TIdFTP.OnWorkEnd
事件处理程序正在尝试进行 UI 更新,但它也在工作线程中 运行,而不是在主 UI 线程中。那不安全。您必须与主 UI 线程同步才能安全地访问 UI。这包括对 MessageDlg()
的调用,这不是线程安全函数。
试试像这样的东西:
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;
如果您使用的 Delphi 版本不支持匿名过程,您可以将 TThread.Queue()
替换为 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;
procedure TfrmNoticeWindow.IdThreadComponent1Run(
Sender: TIdCustomThreadComponent);
begin
IdFtp1.Host := 'ip';
IdFtp1.Username := 'user';
IdFtp1.Password := 'pass';
if aborted then Exit;
try
IdFtp1.Connect;
except
TIdNotify.NotifyMethod(MsgBoxCouldNotConnect);
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;
if aborted then
TIdNotify.NotifyMethod(ResetUiAborted)
else
TIdNotify.NotifyMethod(ResetUiOk);
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);
if (Resp = 'Notice published successfully!') then
TIdNotify.NotifyMethod(MsgBoxPostOk)
else
TIdNotify.NotifyMethod(MsgBoxPostFail);
finally
Params.Free;
end;
end;
我正在使用 IdThreadComponent 执行简单的 ftp 上传到服务器。
ftp上传的代码如下:
procedure TfrmNoticeWindow.IdThreadComponent1Run(
Sender: TIdCustomThreadComponent);
begin
IdFtp1.Host := 'ip';
IdFtp1.Username := 'user';
IdFtp1.Password := 'pass';
try
IdFtp1.Connect;
except
begin
msgDlgBox.MessageDlg('Could not connect!', mtError, [mbOk], 0);
publishing := false;
end;
end;
IdFtp1.Put(txtPath.text, file_name);
IdFtp1.Quit;
IdFtp1.Disconnect;
End;
FtpWorkEnd 如下:
procedure TfrmNoticeWindow.IdFTP1WorkEnd(Sender: TObject;
AWorkMode: TWorkMode);
var
Params : TStringList;
Resp : String;
begin
IdThreadComponent1.Active := false;
Params := TStringList.Create;
Params.Add('enotice_publish='+packet);
if (aborted = true) then
begin
IdFtp1.Quit;
idFtp1.Disconnect;
aborted := false;
uploadGauge.Value := 0;
uploadGauge.Visible := false;
frmNoticeWindow.Height := 512;
btnUpload.Caption := 'Publish';
exit;
end;
Resp := doPost('url', params);
if (Resp = 'Notice published successfully!') then
msgDlgBox.MessageDlg(Resp, mtInformation, [mbOk], 0)
else
msgDlgBox.MessageDlg(Resp, mtError, [mbOk], 0);
frmNoticeWindow.Refresh;
uploadGauge.Value := 0;
uploadGauge.Visible := false;
frmNoticeWindow.Height := 512;
btnUpload.Caption := 'Publish';
publishing := false;
txtPath.Text := '';
txtNoticeHeader.Text := '';
end;
上传完成后,生成 http post 作为响应,我从服务器得到一个字符串 [Success/Failure]。
问题是,在这个 MessageDlg 之后,我的应用程序的组件变成了白色块,应用程序的控件无法再使用。
我确实在表单上尝试了 update(),但没有帮助。
我正在使用 Business Skin Forms 为我的应用程序设计皮肤,线程组件在关闭后弄乱了表单。
TIdThreadComponent.OnRun
事件处理程序在工作线程的上下文中运行,而不是在主 UI 线程中运行。您的所有 TIdFTP
操作在工作线程的上下文中都是 运行,这很好。但是,您的 TIdFTP.OnWorkEnd
事件处理程序正在尝试进行 UI 更新,但它也在工作线程中 运行,而不是在主 UI 线程中。那不安全。您必须与主 UI 线程同步才能安全地访问 UI。这包括对 MessageDlg()
的调用,这不是线程安全函数。
试试像这样的东西:
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;
如果您使用的 Delphi 版本不支持匿名过程,您可以将 TThread.Queue()
替换为 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;
procedure TfrmNoticeWindow.IdThreadComponent1Run(
Sender: TIdCustomThreadComponent);
begin
IdFtp1.Host := 'ip';
IdFtp1.Username := 'user';
IdFtp1.Password := 'pass';
if aborted then Exit;
try
IdFtp1.Connect;
except
TIdNotify.NotifyMethod(MsgBoxCouldNotConnect);
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;
if aborted then
TIdNotify.NotifyMethod(ResetUiAborted)
else
TIdNotify.NotifyMethod(ResetUiOk);
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);
if (Resp = 'Notice published successfully!') then
TIdNotify.NotifyMethod(MsgBoxPostOk)
else
TIdNotify.NotifyMethod(MsgBoxPostFail);
finally
Params.Free;
end;
end;