The question is published on by Tutorial Guruji team.
I’m new with the TAniindicator component, so for testing purposes I have put together a project that will build a listview and display/spin the Aniindicator whilst the listview is being built.
type TLoadThread = class(TThread) public constructor Create; reintroduce; protected procedure Process; procedure Execute; override; end; constructor TLoadThread.Create; begin inherited Create(True); FreeOnTerminate := True; end; procedure TLoadThread.Process; begin Form1.BuildListView; end; procedure TLoadThread.Execute; begin inherited; FreeOnTerminate := True; Synchronize(Process); end; var _loadThread : TLoadThread; procedure TForm1.ThreadTerminated(Sender: TObject); begin AniIndicator1.Enabled := False; AniIndicator1.Visible := False; end; procedure TForm1.BuildListView; var i : integer; LI : TListViewItem; begin Listview1.BeginUpdate; try for i := 1 to 2000 do begin LI := Listview1.Items.Add; LI.Text := 'Listview Item ' + IntToStr(i); end; finally Listview1.EndUpdate; end; end; procedure TForm1.FormCreate(Sender: TObject); begin AniIndicator1.Visible := False; _loadThread := nil; end; procedure TForm1.Button1Click(Sender: TObject); begin _loadThread := TLoadThread.Create; _loadThread.OnTerminate := ThreadTerminated; _loadThread.Start; AniIndicator1.Enabled := True; end;
I thought I was on the right track but this doesn’t appear to work, can anyone explain what I’m doing wrong please?
Answer
Your worker thread is spending all of its time inside of its Process()
method, which is being called by TThread.Synchronize()
so it runs in the main UI thread. Process()
is not processing UI messages, which is why TAniIndicator
does not work.
As-is, your worker thread is completely useless. All of your code is running in the main UI thread. So, you may as well get rid of TLoadThread
altogether:
procedure TForm1.FormCreate(Sender: TObject); begin AniIndicator1.Visible := False; end; procedure TForm1.BuildListView; var i : integer; LI : TListViewItem; begin AniIndicator1.Visible := True; AniIndicator1.Enabled := True; ListView1.BeginUpdate; try for i := 1 to 2000 do begin LI := ListView1.Items.Add; LI.Text := 'ListView Item ' + IntToStr(i); if (i mod 100) = 0 then Application.ProcessMessages; end; finally ListView1.EndUpdate; AniIndicator1.Enabled := False; AniIndicator1.Visible := False; end; end; procedure TForm1.Button1Click(Sender: TObject); begin BuildListView; end;
Otherwise, if you use a thread, do not synchronize the loop itself, only the pieces that actually touch the UI:
type TLoadThread = class(TThread) public constructor Create; reintroduce; protected procedure Execute; override; end; constructor TLoadThread.Create; begin inherited Create(True); FreeOnTerminate := True; end; procedure TLoadThread.Execute; begin Form1.BuildListView; end; var _loadThread : TLoadThread = nil; procedure TForm1.ThreadTerminated(Sender: TObject); begin _loadThread := nil; end; procedure TForm1.FormCreate(Sender: TObject); begin AniIndicator1.Visible := False; end; procedure TForm1.BuildListView; var i : integer; begin TThread.Synchronize(nil, procedure begin AniIndicator1.Visible := True; AniIndicator1.Enabled := True; ListView1.BeginUpdate; end ); try for i := 1 to 2000 do begin TThread.Synchronize(nil, procedure var LI : TListViewItem; begin LI := ListView1.Items.Add; LI.Text := 'ListView Item ' + IntToStr(i); end ); end; finally TThread.Synchronize(nil, procedure begin ListView1.EndUpdate; AniIndicator1.Enabled := False; AniIndicator1.Visible := False; end ); end; end; procedure TForm1.Button1Click(Sender: TObject); begin if _loadThread <> nil then begin _loadThread := TLoadThread.Create; _loadThread.OnTerminate := ThreadTerminated; _loadThread.Start; end; end;