TAniIndicator не вращается — загрузка tlistview

Я новичок в компоненте TAniindicator, поэтому для целей тестирования я собрал проект, который будет создавать список и отображать/вращать Aniindicator во время создания списка.

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;

Я думал, что я на правильном пути, но это не работает, может ли кто-нибудь объяснить, что я делаю неправильно, пожалуйста?


person 6String_Coder    schedule 06.08.2017    source источник


Ответы (1)


Ваш рабочий поток проводит все свое время внутри своего метода Process(), который вызывается TThread.Synchronize(), поэтому он выполняется в основном потоке пользовательского интерфейса. Process() не обрабатывает сообщения пользовательского интерфейса, поэтому TAniIndicator не работает.

Как есть, ваш рабочий поток совершенно бесполезен. Весь ваш код выполняется в основном потоке пользовательского интерфейса. Итак, вы можете вообще избавиться от TLoadThread:

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;

В противном случае, если вы используете поток, не синхронизируйте сам цикл, а только те части, которые действительно касаются пользовательского интерфейса:

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;
person Remy Lebeau    schedule 06.08.2017
comment
У вас есть идеи, почему AniIndicator не появляется, и если я не делаю visible=false; он появляется после завершения всего процесса. Кстати, я использую C++ Builder 10.3.1. - person mesutuk; 22.04.2020
comment
@mesutuk означает, что основной поток пользовательского интерфейса либо не обрабатывает запросы Synchronize(), либо поток просто завершает свою работу до обновления пользовательского интерфейса. - person Remy Lebeau; 22.04.2020
comment
В основном я запускаю SQL на Android и помещаю их в список. Он появляется, когда весь процесс заканчивается не раньше. Я пробовал Application->ProcessMessages(), но тоже не работал. Я также пытался сделать видимым какой-то другой объект, но бесполезно. Есть ли какая-либо команда обновления или что-то еще, чтобы сделать ее видимой до запуска процесса sql. - person mesutuk; 22.04.2020
comment
@mesutuk Мне нужно увидеть настоящий код. Пожалуйста, опубликуйте новый вопрос об этом. - person Remy Lebeau; 22.04.2020
comment
Фактический код не помещается в раздел комментариев. Я задам вопрос после еще нескольких попыток.. Примечание: я не использую потоки.. просто AniIdacator1.Visible= true; AniIdacator1.Enable= true; затем выполните Sql Query и Application->ProcessMessages(), затем, пока я помещаю записи, полученные из sql, в список, а затем закрываю Query и AniIdacator1.Enable= false; AniIdacator1.Visible= ложь; - person mesutuk; 22.04.2020
comment
@mesutuk Фактический код не помещался в раздел комментариев - вы не должны размещать код в комментариях с самого начала. И вы не должны пытаться захватить этот вопрос с новой проблемой. Вот почему я попросил вас опубликовать новый вопрос, где он принадлежит. - person Remy Lebeau; 22.04.2020
comment
извините, я не видел, как вы попросили меня новый пост. еще раз извиняюсь. - person mesutuk; 22.04.2020