有没有办法保存Treeview的项目和数据,以便可以在一个线程中访问它?

时间:2014-02-08 19:37:14

标签: multithreading delphi treeview

TreeView项和数据包含文件名,数据包含TBitmap。我的问题是以某种方式保存树视图中的项目和数据,因此可以在一个线程中访问项目和数据。如果可以,在保存项目和数据后,我可以访问线程中的项目和数据,而不是在Synchronize中访问它。由于在同步中访问GUI TreeItems和Data,因此现在编写的代码太慢了。

if not Terminated then
begin
   Synchronize(
   procedure
   var
     i: integer;
   begin
     for i := 1 to Form1.TreeView1.Items.Count - 1 do
     begin
        { get the bitmap }
        iImageEnIO.WIAParams.ProcessingBitmap := iImageEnIO.IEBitmap;
        { The following line prevents me from accessing the TreeView data in a thread }
        iImageEnIO.WIAParams.Transfer(TIEWiaItem(Form1.TreeView1.Items[i].Data), False);
        { Set the filename }
        iFilename := Form1.TreeView1.Items[i].Text + '.jpg';
        { Add the image to the iIEImageList }
        iIndex := iIEImageList.AppendImageRef(TIEBitmap.Create(iImageEnIO.IEBitmap), iFileName);
        iIEImageList.Filename[iIndex] := iFileName;
     end;
end);

线程代码访问线程中的位图本身效果很好,但是如果我可以将获取位图的代码移动到线程而不是在Synchronize中会更好。所以我的问题是“有没有办法在Synchronize中保存树视图项和数据,以便可以在Synchronize之外的线程中访问它?”

    iImageEnIO.OnProgress := ImageEnProcProgress;
    iImageEnIO.OnFinishWork := ImageEnProcFinishWork;

    { Get the bitmap from the imagelist and save the image in the thread }
    iCount := iIEImageList.ImageCount;
    for j := 0 to iCount-1 do
       begin
         { get the filename from the string list }
         iFilename := iIEImageList.Filename[j];
         { attach the iIEBitmap2 to iImageEnIO }
         iImageEnIO.AttachedIEBitmap := iIEImageList.Image[j];
         iPath := IncludeTrailingPathDelimiter(iFolder) + iFilename;
         iImageEnIO.SaveToFile(iPath); 
      end;

我希望我已经正确地提出了我的问题,很明显我想尝试做什么。

1 个答案:

答案 0 :(得分:3)

我想把它转过来。您想知道在执行线程方法时如何从GUI控件读取数据。这是一个基本的设计缺陷。问题的解决方案将涉及根本不尝试这样做。

树视图不应该是数据的所有者。它是一个GUI控件,应该只显示数据视图。数据应保存在未绑定到VCL线程规则的结构中。一旦将数据结构与GUI分离,您​​的问题就变得微不足道了。一旦达到这一点,就没有问题需要解决。

那么,你需要什么样的结构?虽然它存储在树形视图中,但它似乎是一个平面列表。将其存储在TList<T>容器中。您对T使用了什么?嗯,这只是每个项目所需的信息。这可能是一个记录。或者它可以是一个班级。如果您在项类型中持有非值类型对象,那么类可能更好。在这种情况下,TObjectList<T>更适合。所以,它看起来像这样:

type
  TItem = class
  private
    FFileName: string;
    FBitmap: TBitmap;
  end;

然后你的容器只是TObjectList<TItem>。像这样实例化:

FItems := TObjectList<TItem>.Create(True);

True适用于OwnsObjects参数。这意味着当您从容器中删除项目或删除容器时,项目将被销毁。

此时,您可以通过迭代容器来填充树视图,并创建表示项目的节点。

然后,当您的线程需要对数据进行操作时,它可以引用与GUI控件分离的FItems

故事的寓意是你不应该使用GUI控件作为主要数据容器。