0

クライアントがこのコードと同じように接続したときに、Tabsheetに動的に追加したい:PageControlIdCmdTCPServer

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

問題ありませんが、アプリケーションを閉じると、「システム エラー。コード: 1400。無効なウィンドウ ハンドル」というメッセージが表示された EOSError が表示されます。TButtonのイベントにこのコード ブロックを追加しましたOnClick。アプリケーションは問題なく終了します。これを行うより安全な方法はありますか?


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;

コマンドのテスト結果:

addtab コマンドのテスト結果

しかし、言及された問題は、アプリケーションの終了時に発生する鋼です!

4

2 に答える 2

1

イベント ハンドラーとそれに含まれる VCL アクセス コードは、GUI スレッド以外のスレッドで実行されます。VCL オブジェクトにアクセスするすべてのコードは、GUI スレッドで実行する必要があります。したがって、VCL 部分が GUI スレッドにマーシャリングされるようにコードを変更する必要があります。

TIdSync または TThread.Synchronize を使用して、コードの VCL 部分を GUI スレッドにマーシャリングします。Remy はここで前者のアプローチの例を挙げています: Indy synchronize ServerTCPExecute

于 2013-05-30T08:46:20.243 に答える
0

最終的な正しい考え:

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に特に感謝します

于 2013-05-30T09:54:25.740 に答える