我仍然不太明白如何使用Threads实现多线程

时间:2014-06-28 15:12:24

标签: delphi delphi-xe

对于这个问题,请参阅我前一段时间提出的问题:Do I need TThreads? If so can I pause, resume and stop them? LU RD通过提供的演示和一些评论回答了问题。

我已经停止使用Delphi很长一段时间了,但现在我又回到了它并重做了一个项目。该项目具有耗时的操作,例如打开Gif,提取帧然后将这些帧(位图)添加到TImageList和TListView中。这次我实际上将位图直接添加到TObjectList中,如下所示:How to add and retrieve Bitmaps to and from a TList?

通常没有什么特别的需要在这里加速,因为大多数Gif动画都很小,但是对于中到大的Gif,应用程序可以挂起。这会变得更糟,因为这些位图将在运行时使用各种成像滤镜(如灰度,更改色调等)进行修改。所以我确信我需要多线程,否则访问每个位图然后操作将会非常慢(正如我之前发现的那样)。


所以说,我愚蠢地试图适应(不知道我在做什么)我的一些程序来处理LU RD我在顶部链接的TThread示例。

我希望我花更多时间处理原始问题,以获取更多信息,但我想我已经偏离了一些东西并转移到其他东西上,这意味着我什么都没学到。

从线程示例中获取此片段:

const
  cWorkLoopMax = 500;

function TForm1.HeavyWork: boolean; // True when ready
var
  i, j: integer;
begin
  j := 0;
  for i := 0 to 10000000 do
    Inc(j);
  Inc(workLoopIx);
  Result := (workLoopIx >= cWorkLoopMax);
end;

首先,我不知道cWorkLoopMax是什么,为什么它的值设置为500?

其次我猜HeavyWork程序只是一个样本,它在循环中运行10000000次,同时递增j变量?

然后我们有workLoopIx我不确定是什么用的?也许与线程中的位置有关?


所以,这里我有我当前的代码(没有线程)来处理打开Gif并添加到TListView和TImageList。我使用的程序在另一个单元中,如果需要我也会发布它,但这是我在TAction中使用的内容(actOpen):

if OpenPictureDialog.Execute then
begin
  Screen.Cursor := crHourGlass;
  try
    BitmapCollection.AddFromGif(OpenPictureDialog.FileName, ImageList1);

    ListView1.Items.BeginUpdate;
    try
      ListView1.Items.Clear;

      for I := 0 to BitmapCollection.BitmapList.Count - 1 do
      begin
        with ListView1.Items.Add do
        begin
          Caption := 'bitmap' + IntToStr(I+1);
          ImageIndex := I;
        end;
      end;
    finally
      ListView1.Items.EndUpdate;
    end;
  finally
    Screen.Cursor := crDefault;
  end;
end;

我不明白如何将它放入线程程序,例如HeavyWork?我刚刚创建了一个名为Job_Open的新工具并执行了此操作:

procedure TForm1.actOpenExecute(Sender: TObject);
begin
  if OpenPictureDialog.Execute then
  begin
    if not Assigned(MyThread) then
    begin
      workLoopIx := 0;
      btnStartTask.Enabled := false;
      btnPauseResume.Enabled := true;
      btnCancelTask.Enabled := true;
      MyThread := TWorkerThread.Create(Self.Handle, WM_MyProgress, Job_Open);
    end;
  end;
end;

function TForm1.Job_Open: boolean;
var
  I: Integer;
begin
  BitmapCollection.AddFromGif(OpenPictureDialog.FileName, ImageList1);

  for I := 0 to BitmapCollection.BitmapList.Count - 1 do
  begin
    with ListView1.Items.Add do
    begin
      Caption := 'bitmap' + IntToStr(I+1);
      ImageIndex := I;
    end;
    Inc(workLoopIx);
  end;

  Result := (workLoopIx >= BitmapCollection.BitmapList.Count);// cWorkLoopMax);
end;

这显然不对,性能较慢,我遇到了各种错误,例如无效句柄。

如果有人能花一些时间来解释我的评论,我做错了什么以及我应该做些什么,我会非常感激,欢迎更新源代码和评论,但我希望能够学到更多理想情况下代码发生了什么。

在一个完美的世界中,如果有一个易于使用的存在的库,那么如果我无法理解上面发生的事情那将是一个巨大的帮助。是否有这样的库可以做类似的事情:

procedure DoSomething;
begin
  BeginThreading();
    HeavyWork;
  StopThreading();
end;

提前致谢,并为漫长的帖子道歉。

1 个答案:

答案 0 :(得分:2)

免责声明:虽然我的答案不是您问题的直接答案,但它可以解决您的问题。

在阅读完问题后,我向您提出了一个问题:

您是否在所有ImageList图像上应用相同的图像图形效果?

如果你那么我必须说你开始用错误的方法处理你的问题。

首先,您需要知道Imagelist doesen单独存储所有这些图像,但它们将它们全部存储在相同的宽幅图像中。因此,当您在内部读取任何ImageList图像时,ImageList会创建输出位图,然后使用相当的Canvas.CopyRect。将图像保存到图像列表时,它在内部使用Canvas.Draw。

因此,当您多次执行此操作时,会创建大量不必要的数据移动。

因此,我建议您使用ImageLists内部图像,而不是您处理单独图像的方法,您可以使用ImageList.GetImageBitmap获取句柄。这将使您同时对所有ImageList图像应用相同的图形效果。如果您不需要将图形效果应用于所有ImageList图像,我敢打赌您可以修改您的图像处理方法,使其仅适用于图像的某些部分。

为了了解有关ImageList的更多信息,我重新阅读了您的文档:

图片列表说明:http://docwiki.embarcadero.com/Libraries/XE6/en/Vcl.Controls.TImageList

图片列表GetImageBitmap说明 http://docwiki.embarcadero.com/Libraries/XE6/en/Vcl.ImgList.TCustomImageList.GetImageBitmap