调用Beginthread API时如何避免GUI冻结?

isa*_*isa 0 delphi

下面是2个线程中的2个按钮之间的简单比赛,

这将冻结表单上的其他组件.


procedure moveButton1();
var
  I: Integer;
begin
  for I := 0 to 6000 do
    Form1.Button1.Left := Form1.Button1.Left - 1;
  Form1.Caption := 'Button1 won!';
  EndThread(0);
end;

procedure moveButton2(); var I: Integer; begin for I := 0 to 6000 do Form1.Button2.Left := Form1.Button2.Left - 1; Form1.Caption := 'Button2 won!'; EndThread(0); end;

procedure TForm1.Button3Click(Sender: TObject); var thread1, thread2,tick : Integer; id1, id2 : LongWord; begin thread1 := BeginThread(nil, 0, Addr(moveButton1), nil, 0, id1);

thread2 := BeginThread(nil, 0, Addr(moveButton2), nil, 0, id2); CloseHandle(thread1); CloseHandle(thread2); end;

jpf*_*ius 10

VCL(和部分RTL)不是线程安全的,因此您无法从线程中移动组件.你有几个选择:

  • 使用TTimer组件.您不需要线程,并且计时器的事件处理程序将在主线程的上下文中执行.计时器的设计完全适合这样的事情.
  • 同步线程中所有与VCL相关的内容.TThread提供了一个Synchronize完全正确的静态方法.
  • 使用SendMessage或从线程向表单发送消息,并在表单中PostMessage处理此消息.

在使用线程时,您可能还会考虑使用TThread包装类而不是使用BeginThreadEndThread显式.

  • VCL被设计为仅从一个线程操作,是的,但是大多数RTL是线程安全的 - 取决于使用的定义.例如,肯定不是必须序列化所有RTL函数调用; 内存管理器是线程安全的; 几乎所有例程都是线程安全的,因为很少操作共享状态; 但是当使用Writeln等时,I/O不是以同一文件(或控制台)为目标. (6认同)