在 firemonkey 框架中使用线程

问题描述 投票:0回答:1

有一个主窗体,当您单击按钮时,一个框架会加载到窗体中。

按钮代码:

procedure TMain.ButtonObjectsClick(Sender: TObject);
begin
  TFrameSystems.Execute(LayoutMain,
  procedure(Frame: TFrameSystems)
  begin
    // DoSomething
  end,
  procedure(Frame: TFrameSystems; Success: Boolean)
  begin
    // DoSomething
  end);
end;

框架:

  ...

  TKey = class
    public
      S: string;
      constructor Create(const AStr: string);
  end;

  TFrameSystems = class(TFrameOverlay)
    ...
  private
    ...
    FProcCallback: TProc<TFrameSystems, Boolean>;
    FActiveUser: TUser;
    procedure UpdateBuildingList;
    ...
  public
    constructor Create(AOwner: TComponent); override;
    class procedure Execute(AParent: TControl; ProcSet: TProc<TFrameSystems>; ProcExecuted: TProc<TFrameSystems, Boolean>);
    property ActiveUser: TUser read FActiveUser write FActiveUser;
    ...
    { Public declarations }
  end;
implementation


uses 
 ...
{$R *.fmx}

class procedure TFrameSystems.Execute(AParent: TControl; ProcSet: TProc<TFrameSystems>;
  ProcExecuted: TProc<TFrameSystems, Boolean>);
begin
  var Frame := TFrameSystems.Create(AParent);
  Frame.Parent := AParent;
  Frame.FProcCallback := ProcExecuted;
  Frame.Align := TAlignLayout.Contents;
  Frame.BringToFront;
  if Assigned(ProcSet) then
    ProcSet(Frame);
end;

constructor TFrameSystems.Create(AOwner: TComponent);
begin
  inherited;
  Name := '';
  FActiveUser := ClientModule.User;
  UpdateBuildingList;
end;

procedure TFrameSystems.UpdateBuildingList;
begin
  TThread.CreateAnonymousThread(procedure
  var
    s1: TStrings;
    JSONObject: TJSONObject;
    i: integer;
  begin
    JSONObject := ClientModule.ServerMethodsClient.RefreshUserBuildingList(ActiveUser.id);
    ActiveUser.RefreshBuildingList(JSONObject);
    s1 := TStringList.Create;
    for I := 0 to ActiveUser.BuldingList.Count - 1 do
    begin
    with cb_object_list.Items do
      AddObject(ActiveUser.BuldingList[I].Name, TKey.Create(IntToStr(ActiveUser.BuldingList[I].id)));
      s1.AddObject(ActiveUser.BuldingList[I].Kks, TIntObj.Create(ActiveUser.BuldingList[I].id));
    end;
    Edit1.AssignItems(s1);
  end).Start;

end;


当框架打开时,我需要将一些数据上传到组合框。如果您调用 UpdateBuildingList 函数并且在没有线程的情况下执行此操作,那么程序会冻结一段时间。

我尝试通过向该函数添加匿名线程来解决问题,看起来问题已经解决了。但是,为什么它在没有 TThread.Synchronize 的情况下也能工作?总的来说,我通过创建匿名线程做了正确的事情吗?

delphi firemonkey
1个回答
0
投票

这里的问题是,您正在从辅助线程逐项填充 ComboBox,这是不允许的,并且可能会导致各种问题。

我还看到您正在使用

AddObject
来将对象添加到每个组合框项目。

您应该以安全的不同方式执行此操作。怎么办?

首先为自己创建一个新的字符串列表,然后使用

AddObject
填充它,就像现在填充组合框一样。您可以在辅助线程中自由地执行此操作。

完成后,只需将 StringList 分配给您的

ComboBox.Items
属性即可。您可以在
Synchronize
内执行此操作,以便在主线程内完成。

这是一个快速代码示例:

//Populate StringList with strings and connected objects
SL := TStringList.Create;
SL.AddObject('Panel1',Panel1);
SL.AddObject('Panel2',Panel2);
//Assign StringList to ComboBox.Items property
//This can be done since TStringList is actually descendant class from 
//TStrings which is the property type of ComboBox.Items property
ComboBox1.Items := SL;
© www.soinside.com 2019 - 2024. All rights reserved.