Delphi表单在线程中加载内容时显示进度条

时间:2017-04-05 23:56:06

标签: multithreading delphi

我有一个程序,目前正在转换一些大的UTF16字体文件(大小为兆字节),它们来自一组3。此程序获取这些字体文件,将其缩小为仅使用的字符,并保存所需的字符。程序本身工作正常,但加载过程需要大约25秒的线程和大约40-45秒无线程。我认为在那里有一个进度条来显示加载线程的进度是很好的。我找到了一个指南here,了解如何使用消息处理此问题(无法测试我的解决方案是否正常工作)。

我创建了一个带有三个进度条的新表单,并打算将其连接起来,以便他们在加载时报告进度。问题是,当我在窗体上调用ShowModal方法时,表单加载而没有控件(只是一个空白的白色窗口),加载,当它完成时,控件出现,我可以退出窗口和进程完了。

我的问题是,如何在开始加载之前首先显示所有控件?这是我不太确定如何问(因此解释和问题)和我的研究没有给出任何东西(我猜它是“你需要知道正确的单词”情景之一)。

我尝试过的事情:

  • 将要编写的代码放入OnShow和OnCreate事件中。没有运气。
  • 人们说OnActivate是我应该使用的事件,但使用该事件会产生同样的问题。
  • 试图废除一件事。称为Show(),然后是我的Load()函数,最后是Close()。没有运气。
  • 只需显示()表单,手动执行逻辑,然后关闭()。
  • 彻底浏览本网站
  • 检查Embarcadero是否提供了这样的东西,我不知道(如果我还没有意识到的话)。

我认为这个功能并不重要,但是30秒的阻止很长时间没有注意到某些事情正在发生。

2 个答案:

答案 0 :(得分:-1)

我所做的,不需要线程,就是创建窗口DisableTaskWindows(),用TForm.Repaint()强制重绘,然后完成工作。像这样:

var
  LWindowList: pointer;
  LForm: TProgressForm;
begin
  LForm := TProgressForm.Create(nil);
  try
    LWindowList := DisableTaskWindows(LForm.Handle);
    try
      LForm.Show;

      LForm.Repaint;

      // Do your work here.
      // When updating your UI, be sure to call LForm.Repaint()
      // or Application.ProcessMessages();

    finally
      EnableTaskWindows(LWindowList);
    end;
  finally
    LForm.Free;
  end;
end;

注意:这是直接输入答案的,可能无法编译。

答案 1 :(得分:-1)

您应该做的是将工作线程与UI表单分开。在TThread后代做你的工作。

两者之间的所有通信都应该通过发布异步消息来完成。工作线程应该在启动时向UI发布消息,报告进度以及何时结束。 UI可以使用它来可视化表单,更新进度条并最终关闭表单。如果你需要在UI上有一个用户取消按钮,这应该发送一条消息给它用来中止执行的工作线程。

通过"发布异步消息"我的意思是你要么使用RTL.Messaging之外的消息传递框架(它只处理同步消息),要么至少包含TThread.Queue中的调用。我使用我的消息类解释here

为了处理这项工作,我自己使用这个基类:

  TMEBatchOp = Class(TMELocalizableComponent)
  Private
    FMessageHandler:   TMEMessageHandler;
    FInfo:             TMEBatchOpInfo;
    FLastUpdateStatus: Cardinal;
    FRequestedCancel:  Boolean;
    Procedure CheckCancelled;
    Procedure Run;
    Procedure SetResult(Const Value: TMEBatchOpResult);
    Procedure SetStatus(Const Value: TMEBatchOpStatus);
    Procedure UpdateStatus(Const DelaySecs: Integer = 0);
  Protected
    Function CalcWorkMax: Integer; Virtual;
    Procedure DoExecute; Virtual; Abstract;
    Procedure DoSetup; Virtual;
    Procedure DoTeardown; Virtual;
    Function GetAllowCancel: Boolean; Virtual;
    Function GetDescription: String; Virtual;
    Procedure ReceiveEnvelope(Const Envelope: TMEMessageEnvelope);
    Property MessageHandler: TMEMessageHandler Read FMessageHandler;
    Property Info: TMEBatchOpInfo Read FInfo;
    Property RequestedCancel: Boolean Read FRequestedCancel;
  Public
    Class Procedure CaptureLocalizable(Localizer: TMELocalizer); Override;
    Class Function GetModuleName: String;
    Constructor Create(AOwner: TComponent); Override;
    Procedure Worked(Qty: Integer = 1);
  End;

特定工作线程的实现需要定义TMEBatchOp的子类并实现DoExecute方法。如果需要,还可以重新定义CalcWorkMax,DoSetup和DoTeardown。例如:

Type
  TBatchOpSaveTexts = Class(TMEBatchOp)
  Protected
    Function CalcWorkMax: Integer; Override;
    Procedure DoExecute; Override;
    Function GetDescription: String; Override;
  Public
    Class Procedure CaptureLocalizable(Localizer: TMELocalizer); Override;
  End;

执行此操作只需要这样的调用:

RunAndFree(TBatchOpSaveTexts);

RunAndFree的实现方式如下:

Function RunAndFree(BatchOpClass: TMEBatchOpClass): TMEBatchOpResult; Overload;
Begin
  Result := RunAndFree(BatchOpClass.Create(Nil));
End;

Function RunAndFree(BatchOp: TMEBatchOp): TMEBatchOpResult; Overload;
Begin
  Try
    BatchOp.Run;
    Result := BatchOp.Info.Result;
  Finally
    BatchOp.Free;
  End;
End;

TMEBatchOpInfo包含有关工作结果和状态,时间和工作以及完成和进展的信息。它还包含有关是否可以取消操作的信息。所有消息都包含此信息的副本,因此UI可以相应地更新自身。这是它的界面:

  TMEBatchOpInfo = Class(TMEPersistent)
  Private
    FID:          String;
    FParentID:    String;
    FDescription: String;
    FTimeBegin:   TDateTime;
    FTimeEnd:     TDateTime;
    FResult:      TMEBatchOpResult;
    FWorkMax:     Integer;
    FWorkDone:    Integer;
    FAllowCancel: Boolean;
    FStatus:      TMEBatchOpStatus;
    Function GetDone: Boolean;
  Public
    Constructor Create; Override;
    Procedure Assign(Source: TPersistent); Override;
    Property ID: String Read FID;
    Property ParentID: String Read FID;
    Property Description: String Read FDescription;
    Property TimeBegin: TDateTime Read FTimeBegin;
    Property TimeEnd: TDateTime Read FTimeEnd;
    Property Result: TMEBatchOpResult Read FResult;
    Property WorkMax: Integer Read FWorkMax;
    Property WorkDone: Integer Read FWorkDone;
    Property Done: Boolean Read GetDone;
    Property AllowCancel: Boolean Read FAllowCancel;
    Property Status: TMEBatchOpStatus Read FStatus;
  End;