如何使用Delphi从线程更新GUI [英] How to update GUI from Thread using Delphi
问题描述
我正在使用Delphi匿名线程执行代码. 在线程中间,必须进行几次GUI更新,更改一些标签,等等.
I am using Delphi anonymous thread to execute code. In the middle of the thread, a couple of GUI updates have to take place, a couple of labels changing etc.
如果我从线程内部执行此操作,则会进行更改,但是只要线程停止就进行更改.它们消失了,然后应用程序给了我旧的窗口处理程序错误...(这是可以预料的)
If I do this from inside the thread, the changes take place, but as soon as the thread stops. they disappear, and then the application gives me the old window handler error...(Which is to be expected)
System Error. Code:1400. Invalid window handle
我尝试使用Syncronize(updateui);
方法执行更改(将更改移至单独的功能),但是在同步E2066 Missing operator or semicolon
上收到错误,这对我根本没有意义...
I tried using the Syncronize(updateui);
method to execute the changes(moved them to a separate function), but I get an error on the syncronize E2066 Missing operator or semicolon
which does not make sense to me at all...
我已经一页接一页地搜索了,他们似乎都这样称呼,但是当我这样做时,我得到了上面的错误...
I have searched through page after page, and they all seem to call it this way, but when I do, I get the above error...
我说错了吗?
代码:
TThread.CreateAnonymousThread(
procedure
begin
main.Enabled:=false;
Loading.show;
label52.caption:=getfieldvalue(datalive.users,'users','credit_amount','user_id',user_id );
CoInitialize(nil);
if (length(maskedit1.Text)=maskedit1.MaxLength) and (pingip(serverip)=true) then
begin
if (strtofloat(label52.caption)>0) then
begin
....do some work....
Synchronize(updateui);
end
else Showmessage('Insufficient Funds. Please add funds to continue.');
end
else if (length(maskedit1.Text)<>maskedit1.MaxLength) then
begin
Showmessage('ID Number not long enough.');
end
else
begin
Showmessage('Could not connect to the server. Please check your internet connection and try again.');
end;
CoUnInitialize;
loading.close;
main.Enabled:=true;
end).start;
UpdateUI:
procedure TMain.updateui;
var
birthdate,deathdate:TDate;
begin
Panel3.Show;
Label57.Caption := 'Change 1';
Label59.Caption := 'Change 2';
Label58.Caption := 'Change 3';
Label60.Caption := 'Change 4';
Label62.Caption := 'Change 5';
Label70.Caption := 'Change 6';
ScrollBox1.Color := clwhite;
end;
推荐答案
使用 TThread.Synchronize 并将另一个匿名函数传递给它.然后,您可以在匿名函数中调用 updateui :
Use TThread.Synchronize and pass another anonymous function to it. Then you can call updateui in the anonymous function:
TThread.CreateAnonymousThread(
procedure
begin
// do whatever you want
TThread.Synchronize(nil,
procedure
begin
updateui();
end);
// do something more if you want
end
).Start();
同步通常很昂贵(就性能而言).仅在确实需要它们时才使用它们.如果扩展 updateui 方法以减少绘制操作,则可以提高性能.
Synchronizations are generally expensive (regarding performance). Only do them when they are really neccessary. You can increase the performance if you extend the updateui-method to reduce paint-operations.
可以调用 WM_SETREDRAW :
procedure StopDrawing(const Handle: HWND);
const
cnStopDrawing = 0;
begin
SendMessage(Handle, WM_SETREDRAW, cnStopDrawing, 0);
end;
procedure ContinueDrawing(const Handle: HWND);
const
cnStartDrawing = 1;
begin
SendMessage(Handle, WM_SETREDRAW, cnStartDrawing, 0);
// manually trigger the first draw of the window
RedrawWindow(Handle, nil, 0,
RDW_ERASE or RDW_FRAME or RDW_INVALIDATE or RDW_ALLCHILDREN);
end;
在 updateui()顶部添加对 StopDrawing()的调用,并在< updateui().对 ContinueDrawing()的调用应位于最后-block .这样可以确保即使在执行updateui期间发生异常之后,窗口也将被绘制.
Add a call to StopDrawing() at the top of updateui() and a call to ContinueDrawing() at the end of updateui(). The call to ContinueDrawing() should be in a finally-block. This will ensure that the window will be painted even after an exception has occured during the execution of updateui.
示例:
procedure TMain.updateui;
begin
try
StopDrawing(Handle);
Panel3.Show;
Label57.Caption := 'Change 1';
Label59.Caption := 'Change 2';
// ...
finally
// Code under finally gets executed even if there was an error
ContinueDrawing(Handle);
end;
end;
这篇关于如何使用Delphi从线程更新GUI的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!