如何在TTask(线程)内调用表单?

时间:2017-10-08 05:45:38

标签: multithreading delphi

在Delphi 10中,我有一个FormA,它在iTask(线程)“Tarefaproc”中调用Oracle存储过程。此storedproc更新了一个表格,该表格将由另一个Tchart中的FormB使用。

我在FormB Tarefaproc之后呼叫iTask但是,它不起作用,它冻结了应用程序!!感谢您帮助我们理解并解决了这个问题。

请参阅我的代码:

procedure TFormA.SpeedButtonChamaGrafico(Sender: TObject);
var
   Tarefaproc, Tarefagrafico : iTask;
begin

// Call StoredProc inside iTask ==>  this WORKS PERFECTLY !!

Tarefaproc := TTask.Create( procedure ()
                            begin
                                 with FDStoredProc1 do
                                 begin
                                      Prepare;
                                      Params[0].Value := StrToInt(EditCenario.Text);
                                      Execproc;
                                  end;
                             end);
          Tarefaproc.Start;

// Next, calls FormB inside another iTASK ==> DOESN'T WORK , it frozes the application !

 Tarefagrafico := TTask.Create(
                              procedure ()
                              begin
                                   try
                                      Application.CreateForm(TformB,FormB);
                                      FormB.ShowModal;
                                   finally
                                      Freeandnil(formB);
                                   end;
                              end);
  Tarefagrafico.Start;
end;

1 个答案:

答案 0 :(得分:3)

无法从线程访问VCL。 相反,queue该方法调用模态表单以便稍后在主线程中执行。

procedure TFormA.SpeedButtonChamaGrafico(Sender: TObject);
var
  value : Integer;
begin
  value := StrToInt(EditCenario.Text); // Avoid vcl access from thread !!
  TTask.Create( 
    procedure
      begin
        with FDStoredProc1 do
        begin
          Prepare;
          Params[0].Value := value;
          Execproc;
        end;
        // Next, queue method for later execution in main thread 
        TThread.Queue(nil,
          procedure
          var
            FormB : TFormB; // Use local form variable
          begin
            FormB := TFormB.Create(nil);  // Way to create form dynamically
            try
              // Here you can add data into FormB from the database extraction !!
              // It is safe, since this call is executing in the main thread. 
              FormB.ShowModal;
            finally
              Freeandnil(FormB);
            end;
          end);
      end).Start;
end;

请注意,即使从线程中读取vcl属性也是危险的。 此外,应避免使用全局表单变量。从IDE创建表单时,我要做的第一件事就是删除创建的全局表单变量。

来自TThread.Queue的文档:

  

在主线程中执行方法调用。   队列导致AMethod指定的调用使用主线程异步执行,从而避免多线程冲突。