【问题标题】:How to safe add a Tabsheet to a PageControl in TIdCmdTCPServer OnConnect event?如何在 TIdCmdTCPServer OnConnect 事件中安全地将 Tabsheet 添加到 PageControl?
【发布时间】:2013-05-30 17:54:25
【问题描述】:

当客户端连接到我的IdCmdTCPServer 时,我想将Tabsheet 动态添加到PageControl,与此代码相同:

procedure TForm1.IdCmdTCPServer1Connect(AContext: TIdContext);
var
  ATabSheet: TTabSheet;
begin
  ATabSheet := TTabSheet.Create(PageControl1);
  ATabSheet.PageControl := PageControl1;
  ATabSheet.Caption := 'Hello!';
  {...}
end;

没关系,但是当关闭应用程序时,我会收到 EOSError 消息:“系统错误。代码:1400。无效的窗口句柄”。 我已经在TButtonOnClick 事件中添加了这个代码块,应用程序将毫无问题地关闭。 有没有更安全的方法来做到这一点?


David Heffernan的帮助下,我改变了我的方法:

....

type
  TMyThrd = class(TThread)
    protected
      procedure Execute; override;
  end;

...

procedure TMyThrd.Execute;
begin
  with TTabsheet.Create(Form1.PageControl1) do
    PageControl := Form1.PageControl1;
end;

...

procedure TForm1.cmdAddTabCommand(ASender: TIdCommand);
begin
  with TMyThrd.Create(True) do
  begin
    FreeOnTerminate := True;
    Resume;
  end;
end;

及命令测试结果:

但提到的问题是在应用程序关闭时发生钢铁!

【问题讨论】:

  • 也许这会有所帮助stackoverflow.com/q/9139940/1699210
  • @bummi:谢谢你的建议。但我检查了我的 TCP 部分代码,并且在 OnConnect 事件中没有此块代码,它们运行完美。只是当我添加这个块时,就会出现问题!

标签: delphi tcpserver tpagecontrol system-error ttabsheet


【解决方案1】:

您的事件处理程序以及它所包含的 VCL 访问代码在 GUI 线程以外的线程上执行。所有访问 VCL 对象的代码都必须在 GUI 线程上执行。因此,您需要更改代码以确保将 VCL 部分编组到 GUI 线程。

使用 TIdSync 或 TThread.Synchronize 将代码的 VCL 部分编组到 GUI 线程上。雷米在这里给出了前一种方法的一个例子:Indy synchronize ServerTCPExecute

【讨论】:

  • 你必须按照我在答案中所说的去做。调用 TThread.Synchronize。不要创建另一个线程!
  • 哪个线程?你说的TThread是一个类,我到底要根据这个类同步哪个标识符?
  • 使用类方法 TThread.Synchronize。或者雷米在我的回答链接的问题中描述的变体。但是现在您需要停止使用试错法,并阅读线程的基础知识、同步的概念以及为什么需要它。在继续之前,您需要了解。
  • 坦克很多!我已经按照 Remy 的想法更改了我的代码,这次没有看到错误 1400 消息,但是在关闭应用程序时会发生“无效操作句柄”!
【解决方案2】:

最终正确的想法:

uses
..., IdSync, ...
...

type
  TSyncThrd = class(TIdSync)
  protected
    procedure DoSynchronize; override;
end;

...

procedure TForm1.cmdAddTabCommand(ASender: TIdCommand);
begin
  with TSyncThrd.Create do
  begin
    try
      Synchronize;
    finally
      Free;
    end;
  end;
end;

...


procedure TSyncThrd.DoSynchronize;
begin
  with TTabsheet.Create(Form1.PageControl1) do
    PageControl := Form1.PageControl1;
end;

当然,当前连接必须在应用程序关闭之前关闭。如果没有,就会出现invalid pointer operation

特别感谢David Heffernan

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-01-09
    • 1970-01-01
    • 2013-07-10
    • 1970-01-01
    相关资源
    最近更新 更多