如果有人想知道,该解决方案实施起来相当简单。我们现在有一个工作已用时间时钟 [0:00],只要客户端应用程序等待 DataSnap 服务器为请求提供服务,它就会递增。本质上,这就是我们所做的。(特别感谢那些分享他们的解决方案的人——这有助于指导我的思考。)
服务器生成的类(ProxyMethods)必须在 VCL 线程中创建,但在单独的线程中执行。为此,我们创建了一个 ProxyMethods 包装类和一个 ProxyMehtods 线程类(所有这些都是为本示例设计的,但仍说明了流程):
代理方法.pas
...
type
TServerMethodsClient = class(TDSAdminClient)
private
FGetDataCommand: TDBXCommand;
public
...
function GetData(Param1: string; Param2: string): string;
...
end;
代理包装器.pas
...
type
TServerMethodsWrapper = class(TServerMethodsClient)
private
FParam1: string;
FParam2: string;
FResult: string;
public
constructor Create; reintroduce;
procedure GetData(Param1: string; Param2: string);
procedure _Execute;
function GetResult: string;
end;
TServerMethodsThread = class(TThread)
private
FServerMethodsWrapper: TServerMethodsWrapper;
protected
procedure Execute; override;
public
constructor Create(ServerMethodsWrapper: TServerMethodsWrapper);
end;
implementation
constructor TServerMethodsWrapper.Create;
begin
inherited Create(ASQLServerConnection.DBXConnection, True);
end;
procedure TServerMethodsWrapper.GetData(Param1: string; Param2: string);
begin
FParam1 := Param1;
FParam2 := Param2;
end;
procedure TServerMethodsWrapper._Execute;
begin
FResult := inherited GetData(FParam1, FParam2);
end;
function TServerMethodsWrapper.GetResult: string;
begin
Result := FResult;
end;
constructor TServerMethodsThread.Create(ServerMethodsWrapper: TServerMethodsWrapper);
begin
FServerMethodsWrapper := ServerMethodsWrapper;
FreeOnTerminate := False;
inherited Create(False);
end;
procedure TServerMethodsThread.Execute;
begin
FServerMethodsWrapper._Execute;
end;
可以看到我们将 ProxyMethod 的执行分为两步。第一步是将参数的值存储在私有变量中。这允许该_Execute()
方法在执行实际的 ProxyMethods 方法时拥有它需要知道的一切,其结果存储在其中以FResult
供以后检索。
FProcID
如果 ProxyMethods 类具有多个函数,您可以轻松地包装每个方法并在调用该方法以设置私有变量时设置一个内部变量(例如)。这样,该_Execute()
方法可以FProcID
用来知道要执行哪个 ProxyMethod...
您可能想知道为什么线程不释放自己。原因是当线程进行自己的清理时,我无法消除错误“线程错误:句柄无效(6) ”。
调用包装类的代码如下所示:
var
smw: TServerMethodsWrapper;
val: string;
begin
...
smw := TServerMethodsWrapper.Create;
try
smw.GetData('value1', 'value2');
// start timer here
with TServerMethodsThread.Create(smw) do
begin
WaitFor;
Free;
end;
// stop / reset timer here
val := smw.GetResult;
finally
FreeAndNil(smw);
end;
...
end;
暂停代码执行,WaitFor
直到 ProxyMethods 线程完成。这是必要的,因为smw.GetResult
在线程完成执行之前不会返回所需的值。在代理执行线程繁忙时使经过时间时钟 [0:00] 递增的关键是使用 aTJvThreadTimer
来更新 UI。即使 ProxyMethod 在单独的线程中执行, ATTimer
也不起作用,因为 VCL 线程正在等待WaitFor
,因此在TTimer.OnTimer()
完成之前不会执行WaitFor
。
从信息上看,TJvTheadTimer.OnTimer()
代码如下所示,它更新了应用程序的状态栏:
var
sec: Integer;
begin
sec := DateUtils.SecondsBetween(Now, FBusyStart);
StatusBar1.Panels[0].Text := Format('%d:%.2d', [sec div 60, sec mod 60]);
StatusBar1.Repaint;
end;