基本上,我需要做的是:
在主表单的顶部向用户显示一个“Please wait ...”表单(我们称之为waitForm
),执行http方法(get和post),并在获得http响应后关闭waitForm
。
由于http post方法与物理设备通信,因此返回响应需要一段时间(这就是为什么我在工作线程中执行此操作,因此主线程不会出现“未响应”)。
我已经将http超时设置为1分钟,并尝试使用匿名线程来执行http方法,以便应用程序不会进入“无响应”状态,到目前为止,它的工作符合预期。
这里我的问题是,我需要在线程完成后在应用程序中进一步使用该响应字符串。这是我到目前为止的代码:
function TForm1.test: string;
var
ReqStream, ResStream: TStringStream;
http: TIdhttp;
command, commandName: string;
begin
TThread.CreateAnonymousThread(
procedure
begin
TThread.Synchronize(nil,
procedure
begin
waitForm.Label1.Caption := 'Please wait ...';
waitForm.BitBtn1.Enabled := False;
waitForm.FormStyle := fsStayOnTop;
waitForm.Show;
end);
try
http := TIdHTTP.Create(nil);
ReqStream := TStringStream.Create('', TEncoding.UTF8);
ResStream := TStringStream.Create('', TEncoding.UTF8);
try
command := '{"Amount":"69.00","TerminalName":"SIMULATE","omitSlipPrintingOnEFT":"1"}';
commandName := 'sale';
http.Request.ContentType := 'application/json';
http.Request.CharSet := 'utf-8';
http.Request.ContentEncoding := 'utf-8';
http.Request.Accept := 'application/json';
http.Request.Connection := 'keep-alive';
http.ConnectTimeout := 60000;
http.ReadTimeout := 60000;
ReqStream.WriteString(command);
ReqStream.Position := 0;
try
http.Post('http://localhost:5555/' + CommandName, ReqStream, ResStream);
http.Disconnect;
self.result := ResStream.DataString; // I know this can't be written like that
except
//
end;
finally
FreeAndNil(ReqStream);
FreeAndNil(http);
end;
finally
TThread.Synchronize(nil,
procedure
begin
waitForm.FormStyle := fsNormal;
waitForm.BitBtn1.Enabled := True;
waitForm.Close;
end);
end;
end).Start;
ShowMessage(result); // this is where I call next procedure to parse the response.
end;
在我们从test()
函数得到结果之后,我需要解析它并在应用程序中进一步使用它。fsStayOnTop
和禁用按钮是我发现的阻止用户与主窗体交互的唯一解决方案,因为.ShowModal
不是一个选项,因为它阻止了即使使用Synchronize()
也无法继续执行函数(我错了吗?)。
我也试过使用ITask
和IFuture<string>
,但似乎不能让它像预期的那样工作。也许我应该使用匿名函数。
2条答案
按热度按时间lf3rwulv1#
如果你想让
TForm1.test()
在内部使用工作线程的同时 * 同步 * 工作,你必须等待工作线程完成,然后才能退出函数。这也允许你的匿名过程捕获一个局部变量,然后你可以在线程完成后将该变量赋值给函数的Result
。试试类似这样的东西:
否则,你应该打破你的逻辑,让
TForm1.test()
以异步方式工作,并让它在线程完成并且响应可用时通知你的代码,例如:话虽如此
我是在一个辅助线程中执行此操作的,因此主线程不会显示为“无响应”
虽然这总体上是个好主意,但我只想指出Indy确实有一个
TIdAntiFreeze
组件来解决这个问题。您可以让test()
函数在不使用工作线程的情况下 * 同步 * 工作,让TIdAntiFreeze
在TIdHTTP
阻塞主线程的同时抽取主消息队列。例如:
aiazj4mn2#
您可以在回调中检索线程执行结果:
注意,把整个线程执行代码放在
TThread.Synchronize
中是没有意义的。同步执行主线程中的代码,所以它将像没有线程一样工作。这只是一个工作证明,我不确定我会在真实的的场景中使用这个设计。