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

时间:2010-03-24 14:02:19

标签: delphi

下面只是两个线程中的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;

2 个答案:

答案 0 :(得分:10)

VCL(以及部分RTL)不是线程安全的,因此您无法从线程中移动组件。您有几种选择:

  • 使用TTimer组件。您不需要线程,并且计时器的事件处理程序将在主线程的上下文中执行。计时器的设计完全符合这类。
  • 同步线程中所有与VCL相关的内容。 TThread提供了一种静态方法Synchronize
  • 使用SendMessagePostMessage将消息从帖子发送到表单,并在表单中处理此消息。

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

答案 1 :(得分:0)

使用Synchronize()将是同步移动按钮的过程的向下和脏的方法。 Synchronize()强制该方法在主VCL线程中运行。它们会相互阻挡,因此一次只能移动一个按钮。这样可以避免在VCL中遇到非线程安全的代码。

我无法重新创建表单冻结的问题,所以我不确定这是你的问题。你可能希望到别处去看看。