Reputation: 547
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?
Upvotes: 1
Views: 1326
Reputation: 596156
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;
Upvotes: 2