Delphi 如何在TIdCmdTCPServer OnConnect事件中将选项卡页安全添加到PageControl?

Delphi 如何在TIdCmdTCPServer OnConnect事件中将选项卡页安全添加到PageControl?,delphi,tcpserver,tpagecontrol,system-error,ttabsheet,Delphi,Tcpserver,Tpagecontrol,System Error,Ttabsheet,当客户端连接到我的IdCmdTCPServer时,我想将选项卡页动态添加到页面控件,与此代码相同: procedure TForm1.IdCmdTCPServer1Connect(AContext: TIdContext); var ATabSheet: TTabSheet; begin ATabSheet := TTabSheet.Create(PageControl1); ATabSheet.PageControl := PageControl1; ATabSheet.Cap

当客户端连接到我的
IdCmdTCPServer
时,我想将
选项卡页
动态添加到
页面控件
,与此代码相同:

procedure TForm1.IdCmdTCPServer1Connect(AContext: TIdContext);
var
  ATabSheet: TTabSheet;
begin
  ATabSheet := TTabSheet.Create(PageControl1);
  ATabSheet.PageControl := PageControl1;
  ATabSheet.Caption := 'Hello!';
  {...}
end;
没问题,但当关闭应用程序时,我会收到一条错误消息:“系统错误。代码:1400。无效的窗口句柄”。 我已经在
TButton
OnClick
事件中添加了这个代码块,应用程序将毫无问题地关闭。 有没有更安全的方法


在他的帮助下,我改变了我的方法:

....

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;
和命令测试结果:


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

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

使用TIdSync或TThread.Synchronize将代码的VCL部分封送到GUI线程。雷米在这里给出了前一种方法的示例:

最终正确的想法:

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;
当然,当前连接必须在应用程序关闭之前关闭。如果否,
将发生无效指针操作


特别感谢

也许这会有所帮助@bummi:谢谢你的建议。但是我检查了我的TCP部分代码,在
OnConnect
事件中没有这个块代码,它们运行得很好。当我添加此块时,问题就会出现!你必须按照我在回答中说的去做。调用TThread.Synchronize。不要再创建另一个线程!哪根线?你说的
TThread
是一个类,我必须同步基于这个类的哪个标识符?使用类方法TThread.synchronize。或者是雷米在我回答的问题中描述的变体。但是现在你需要停止使用试错法,阅读线程的基础知识,同步的概念以及为什么需要同步。在你继续之前你需要理解。很多!我已经改变了我的代码和雷米的想法一样,这次没有看到错误消息,但是关闭应用程序时会出现“无效操作句柄”!