我写了下面一个线程类,该线程从数据库中取出数据,最终将取出的数据加载到主线程的一个combobox控件中。加载到combobox控件的Objects列表中是一个组件对象。在主线程中,当选择combobox控件选项时,会将该combobox控件选项包含的组件显示到窗体界面上。存在的问题是:组件显示到窗体上之后,组件内包含多个组件中的部分组件显示不正常。
如果不用多线程,直接在主线程中以相同的方式加载数据后,完全正常。  TLoadComponentThread =  class(TThread)
  private
    ComponentList: TComboBox;    InComponentList: TStringList;
    ADOQuery: TADOQuery;
  protected
    procedure Execute; override;  
    destructor Destroy; override;
    procedure GetComponent;
    procedure SetToMainList;      //将所获取到的对象列表加载至主线程的对象列表中
  public
    constructor Create(aComponentList: TComboBox; aConnection: TADOConnection);
  end;
  
  
  
{ TLoadComponentThread }
constructor TLoadComponentThread.Create(aComponentList: TComboBox; aConnection: TADOConnection);
begin
  InComponentList := TStringList.Create;
  ADOQuery := TADOQuery.Create(nil);
  ADOQuery.Connection := aConnection;  ComponentList := aComponentList;  FreeOnTerminate := True;
  inherited Create(False);
end;destructor TLoadComponentThread.Destroy;
var
  i: Integer;
begin
  FreeAndNil(InComponentList);
  FreeAndNil(ADOQuery);
  inherited;
end;procedure TLoadComponentThread.Execute;
begin
  inherited;  GetComponent;
end;
//在此过程中将数据库中取出的数据加载到InComponentList
procedure TLoadComponentThread.GetComponent;
var
  i: Integer;
  BlobStream: TADOBlobStream;
  aHouse: TComponentHouse;
begin
  //获取数据
  ADOQuery.SQL.Text := 'SELECT * FROM S_Component';
  if ADOQuery.Active then ADOQuery.Close;
  ADOQuery.Open;  //将数据库中取出的数据加载到InComponentList
  for i := 0 to ADOQuery.RecordCount - 1 do
  begin
    if Terminated then Exit;
  
  //此处的'COMPONENT'字段保存了一个Panel组件,该Panel组件上有若干Panel或Image组件 
    BlobStream := TADOBlobStream.Create(TBlobField(ADOQuery.FieldByName('COMPONENT')), bmRead);
    try
      aHouse := BlobStream.ReadComponent(aHouse) as TComponentHouse;
      aHouse.BindEven;
      InComponentList.AddObject(aHouse.ComponentHouseName, aHouse);
      aHouse := nil;
    finally
      BlobStream.Free;
    end;    ADOQuery.Next;
  end;  Synchronize(SetToMainList) ;
end;//将InComponentList中的数据转移到主线程的ComponentList
procedure TLoadComponentThread.SetToMainList;
var
  i: Integer;
begin
  for i := 0 to InComponentList.Count - 1 do
  begin
    if Terminated then Exit;    ComponentList.Items.AddObject(InComponentList.Strings[i], (InComponentList.Objects[i] as TComponentHouse));
    FToMainIndex := i;
  end;
  
end;

解决方案 »

  1.   

    多线程中操作VCL是不安全的 使用同步方法
    具体可以看delphi自带的demo
      

  2.   

    就是参照那个demo做的,还参照了其他一些资料,那位有相关经验,还望帮忙看看,谢谢了!
      

  3.   

    GetComponent 中的Synchronize(SetToMainList) 后面加一段延时看看,有可能主进程还在转移数据的时候,该线程就结束了。
      

  4.   

    谢谢haozi168 ,我试过了,还是不行
      

  5.   

    设置多个断点跟踪下看InComponentList是否加载到了完整的数据,判断到出错的地方就成功了大半了
      

  6.   

    因为每个list的item.object中包含了一个Panel组件,该Panel组件上有若干Panel或Image组件,
    而只是个别image控件显示不正常,比如一个Panel组件上有四个子Panel组件,每个子Panel上有五个Image组件,总共4×5=20个image中有一二个显示不正常 ,所以我无法通过设断点来看到是否加载完全。
      

  7.   

    procedure TLoadComponentThread.Execute; 
    begin 
      inherited;  Synchronize(GetComponent); //   就同步他
    end; 或者:FreeOnTerminate := flase;   
    同  數據加載後完再關閉這個線程。
      

  8.   

    问题已经解决,我用的是image,通过canvas在其上画图,canvas是非线程安全的,所以在操作canvas时,必须lock,unlock