【问题标题】:TAniIndicator not spinning - loading a tlistviewTAniIndicator 不旋转 - 加载 tlistview
【发布时间】:2017-08-06 17:48:21
【问题描述】:

我是 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;

我以为我在正确的轨道上,但这似乎不起作用,谁能解释我做错了什么吗?

【问题讨论】:

    标签: android delphi firemonkey delphi-10.2-tokyo


    【解决方案1】:

    您的工作线程将所有时间都花在其 Process() 方法中,该方法由 TThread.Synchronize() 调用,因此它在主 UI 线程中运行。 Process() 不处理 UI 消息,这就是 TAniIndicator 不起作用的原因。

    按原样,您的工作线程完全没用。您的所有代码都在主 UI 线程中运行。所以,你不妨干脆干掉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;
    

    否则,如果你使用线程,不要同步循环本身,只同步实际接触 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;
    

    【讨论】:

    • 你知道为什么 AniIndicator 没有出现吗,如果我不做 visible=false;它出现在整个过程完成后。顺便说一句,我使用 C++ Builder 10.3.1
    • @mesutuk 这意味着主 UI 线程要么未处理 Synchronize() 请求,要么线程只是在 UI 更新之前完成其工作。
    • 基本上我在 android 上运行 SQL 并将它们放入列表视图中。它确实出现在整个过程未完成之前。我确实尝试过 Application->ProcessMessages() 但也没有用。我还尝试了其他一些对象以使其可见但没有用。在sql进程开始之前是否有任何更新命令或其他东西使其可见。
    • @mesutuk 我需要查看实际代码。请发布一个关于此的新问题。
    • 实际代码不适合 cmets 部分。我会在多试几次后提出问题。注意:我不使用线程 .. 只是 AniIdacator1.Visible= true; AniIdacator1.Enable=真;然后执行 Sql Query 和 Application->ProcessMessages() 然后在我将从 sql 中获取的记录放入列表视图中,然后关闭 Query 和 AniIdacator1.Enable=false; AniIdacator1.Visible=false;
    猜你喜欢
    • 2014-11-01
    • 1970-01-01
    • 2017-06-15
    • 2017-01-24
    • 2019-02-20
    • 1970-01-01
    • 1970-01-01
    • 2017-08-26
    • 2018-06-22
    相关资源
    最近更新 更多