Animation is not working because thread is doing very little work besides queuing work to the main thread. This gives very little chance to the main thread to do anything besides processing the queued work and repaint animation. This is matter of timing so it is not surprising that you have different behavior on different platforms.
You can either use ProcessMessages to force main thread message processing and repainting the animation, or you can put thread to sleep for short period of time. However, sleeping will slow down the whole process, so you don't want to call it at every iteration.
Following code works without issues.
There are some additional notes, some already mentioned by @Remy Lebeau
First, I have changed StopThread procedure to just call FreeAndNil(FMyThread) - freeing the thread will also call Terminate and WaitFor - this is why it causes the deadlock is you are using Synchronize. Niling the thread is there so you can click the button again otherwise you would leak the thread.
If the thread is already running you will not be able to start the thread again, but you will be able to do so after the first thread is finished. NotifyComplete procedure will also call StopThread to release the thread because it makes no sense to keep dead thread around.
Calling TThread.Queue(TThread.CurrentThread will discard any queued events after the thread is dead. In this example it is important to do so, because form is closing any we don't want to run any already queued events after form is released as this would cause AV. If there is something that needs to be always executed then such code should be in OnTerminate event. When it comes to anonymous method variable capture, they will be captured and their lifetime will be extended, but that only means variable will be accessible, but does not guarantee that the content (object) will be alive, you can only safely use variables of value types and managed types. For others, you need to be sure that they will be alive as long as anonymous method is running. In this case ListView1 and Button2 will not be alive when the form is closed.
procedure TForm1.FormClose(Sender: TObject; var Action: TCloseAction);
begin
StopThread;
end;
procedure TForm1.StopThread;
begin
FreeAndNil(FMyThread);
end;
procedure TForm1.NotifyComplete;
begin
AniIndicator1.Visible := False;
AniIndicator1.Enabled := False;
ListView1.EndUpdate;
ListView1.Enabled := true;
StopThread;
end;
procedure TForm1.Button2Click(Sender: TObject);
begin
if Assigned(FMyThread) then
Exit;
AniIndicator1.Visible := True;
AniIndicator1.Enabled := True;
ListView1.Enabled:=false;
ListView1.BeginUpdate;
FMyThread:=TThread.CreateAnonymousThread(procedure ()
var
I: Integer;
Total: Integer;
begin
Total := 0;
for I := 1 to MaxValue do
begin
TThread.Queue(TThread.CurrentThread,
procedure ()
begin
ListView1.Items.Add.Text := 'Th: ' + I.ToString;
Button2.text:= i.tostring;
end);
if Application.Terminated then
begin
break;
end
else
begin
if i mod 10 = 0 then
Sleep(1);
end;
end;
TThread.Queue(TThread.CurrentThread,
procedure()
begin
ListView1.Items.Add.Text := 'Thread: ' + Total.ToString;
NotifyComplete;
end);
end);
FMyThread.FreeOnTerminate := False;
FMyThread.Start;
end;