【问题标题】:IdHttpServer form caption not updatingIdHttpServer 表单标题未更新
【发布时间】:2012-03-20 09:34:04
【问题描述】:

我知道我之前发布过类似的问题,但我无法让它工作我有这个简单的代码:

procedure TfrmMain.srvrConnect(AContext: TIdContext); //idhttpserver on connect event
var
  S,C : String;
begin
 repeat
  s := s + AContext.Connection.Socket.ReadChar;
 until AContext.Connection.Socket.InputBufferIsEmpty = True;
 frmMain.caption := S;
 Memo1.Lines.Add(S);
end;

备忘录中的字符串显示正常,但标题没有更新

【问题讨论】:

  • IIRC IdHTTPServer 的读/写应该发生在上下文中,所以你需要创建一个 TIdContext 的子类,它将处理服务器创建的线程中的请求/响应,然后你可以为所欲为,这是我前段时间写的一个小demo delphigeist.com/2010/12/…

标签: delphi indy


【解决方案1】:

TIdHTTPServer 是一个多线程组件。 TIdContext 在自己的工作线程中运行。您不能从主线程外部安全地更新表单的Caption(或对 UI 执行任何其他操作)。您需要与主线程同步,例如与TIdSyncTIdNotify 类。

附带说明,在循环中调用ReadChar() 效率非常低,更不用说如果您使用的是Delphi 2009+ 则容易出错,因为它无法返回代理对的数据。

改用类似的东西;

type
  TDataNotify = class(TIdNotify)
  protected
    Data: String;
    procedure DoNotify; override;
  public
    constructor Create(const S: String);
    class procedure DataAvailable(const S: String);
  end;

constructor TDataNotify.Create(const S: String);
begin
  inherited Create;
  Data := S;
end;

procedure TDataNotify.DoNotify;
begin
  frmMain.Caption := Data; 
  frmMain.Memo1.Lines.Add(Data); 
end;

class procedure TDataNotify.DataAvailable(const S: String);
begin
  Create(S).Notify;
end;

procedure TfrmMain.srvrConnect(AContext: TIdContext); //idhttpserver on connect event 
var 
  S: String; 
begin 
  AContext.Connection.IOHandler.CheckForDataOnSource(IdTimeoutDefault);
  if not AContext.Connection.IOHandler.InputBufferIsEmpty then
  begin
    S := AContext.Connection.IOHandler.InputBufferAsString; 
    TDataNotify.DataAvailable(S); 
  end;
end; 

【讨论】:

  • 奇怪但我没有收到任何 AContext.Connection.IOHandler.InputBufferAsString;如果我使用我写的东西就可以了……知道为什么吗?
  • InputBufferAsString 获取InputBuffer 中当前的任何内容并将其转换为String。在 D2009+ 上,这涉及将字节解码为 Unicode。如果解码失败,例如字节包含不完整的字符序列,则可能导致返回空白String。在内部,解码基于 Embarcadero 的 TEncoding 类,这些类不会引发解码错误异常。所以真正的问题是 - 你首先要接收什么样的数据,为什么要一次读取一个字符?
  • 我正在从 GPS 接收数据,因此字符串不像 ascii 那样编码
  • 它仍然必须有一些结构,GPS 不会只是抽出随机数据。你能举例说明数据的实际样子吗?
  • 如果字符串总是以# 字符结尾,则使用ReadLn('#') 并单独保留InputBuffer,例如:s := AContext.Connection.IOHandler.ReadLine('#')。即使该行确实以 00 字节结尾,您也可以改用 ReadLn(#0)
【解决方案2】:

首先,确保您正在写入正确的变量。您确定 frmMain 是您想要更改标题的形式吗?

另外,你可以试试:

procedure TfrmMain.srvrConnect(AContext: TIdContext); //idhttpserver on connect event
var
  S,C : String;
begin
 repeat
  s := s + AContext.Connection.Socket.ReadChar;
 until AContext.Connection.Socket.InputBufferIsEmpty = True;
 oCaption := S;
 TThread.Synchronize(nil, Self.ChangeCaption);
end;

procedure TfrmMain.ChangeCaption;
begin
 Self.Caption := oCaption;
 Memo1.Lines.Add(oCaption);
end;

最后,确保S 的第一行不是空行,因为表单的标题不会显示包含换行符的字符串。

【讨论】:

  • 您无法从工作线程(TIdContext 运行在其中)安全地更新 UI,并且从工作线程调用时Application.ProcessMessages() 不会更新主 UI。
  • TForm 没有Synchronize() 方法,并且ChangeCaption() 不是TfrmMain 类的成员。我更新了你的答案。
  • @RemyLebeau 谢谢!更新代码的时候很着急,没有用Delphi。
猜你喜欢
  • 2021-05-17
  • 2020-10-06
  • 1970-01-01
  • 2022-12-04
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多