Как безопасно добавить Таблицу в PageControl в событии TCond Onernect TIdCmdTCPServer?

Я хочу добавить Tabsheet динамически к PageControl когда клиент подключился к моему IdCmdTCPServer такой же, как этот код:

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

Это нормально, но при закрытии приложения я получаю EOSError с сообщением: "Системная ошибка. Код: 1400. Недопустимый дескриптор окна". Я был добавлен этот блок кода в TButton"s 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

но упомянутая проблема - сталь, происходящая при закрытии приложения!

2 ответа

Решение

Ваш обработчик событий и, следовательно, код доступа к VCL, который он содержит, выполняется в потоке, отличном от потока GUI. Весь код, который обращается к объектам VCL, должен выполняться в потоке GUI. Следовательно, вам нужно будет изменить свой код, чтобы убедиться, что части VCL перенаправляются в поток GUI.

Используйте TIdSync или TThread.Synchronize, чтобы маршалировать части VCL вашего кода в поток GUI. Реми приводит пример первого подхода здесь: Indy synchronize ServerTCPExecute

Окончательная правильная идея:

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

Другие вопросы по тегам