Multithreading – how to update GUI from thread using Delphi
I am using Delphi anonymous thread to execute code
If I do this from within the thread, changes will occur, but once the thread stops They disappeared, and then the application gave me an old window handler error... (this is expected)
System error No.: 1400 Invalid window handle
I try to use synchronize (update UI); Execute the changed methods (move them to a separate function), but I get an error on the syncronize e2066 missing operator or semicolon, which makes no sense to me
I searched page after page, and they seemed to call it that, but when I did, I got the above error
Am I wrong?
Code:
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'; Scroll@R_495_2419@1.Color := clwhite; end;
Solution
Use TThread Synchronize and pass another anonymous function You can then 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();
Synchronization is usually expensive (about performance) They can do it only when they really need it If you extend the updateui method to reduce drawing operations, you can improve performance
This can be done via WM_ Setredraw calls SendMessage:
procedure StopDrawing(const Handle: HWND); const cnStopDrawing = 0; begin SendMessage(Handle,WM_SETREDRAW,cnStopDrawing,0); end; procedure ContinueDrawing(const Handle: HWND); const cnStartDrawing = 0; begin SendMessage(Handle,cnStartDrawing,0); // manually trigger the first draw of the window RedrawWindow(Handle,nil,RDW_ERASE or RDW_FRAME or RDW_INVALIDATE or RDW_ALLCHILDREN); end;
Add a call to stopdrawing () at the top of updateui () and call continuedrawing () at the end of updateui () The call to continuedrawing () should be in finally - block This ensures that the window is drawn even after an exception occurs during the update UI execution
Example:
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;