显示耗时过程的进度

时间:2009-10-19 20:58:02

标签: delphi user-interface dialog

抱歉我的英语不好...... 使用Delphi 7我想创建一个对话框窗口,以显示当我必须运行慢进程时我的应用程序中发生了什么。 我的想法是做一些我可以使用的东西:

with TMyDialog.Create do
begin
  //call the time consuming method here
  Free;
end;

当我创建对话框时,会显示一个带动画或其他内容的窗口,并且会在耗时的方法结束后消失(在免费方法上) - 如果我可以手动更新该对话框的进度,那将会很好这个过程给我这样的信息:

with TMyDialog.Create do
begin
  while time_consuming_method do
  begin
    UpdateStatusOnMyDyalog();
  end;
  Free;
end;

但通常它只是一个动画来表明事情正在发生。

有人做了类似的事情,知道某个组件或有什么建议,以最干净,最简单的方式做到最好吗?

4 个答案:

答案 0 :(得分:3)

您需要在单独的线程中运行耗时的进程,并让该线程使用同步向主UI线程报告其进度。

Here is an example向您展示如何启动新线程并让该线程执行同步进度报告。

- 的Jeroen

答案 1 :(得分:3)

执行此操作的简单方法是致电Application.ProcessMessagesUpdateWindow(Handle)(更新表单)并在time_consuming_method期间增加进度条。稍微好一点的方法是将time_consuming_method包装到具有OnProgress事件的类中。最后,正如其他人建议您可以为time_consuming_method使用单独的线程 - 这是最强大的技术,但学习曲线最差。

答案 2 :(得分:2)

以这种方式报告进度是很常见的(例如,使用进度条)。

您的“耗时过程”需要接收一个回调函数,该函数将在每次报告进度时调用,或者如果您愿意将其与用户界面设计更紧密地绑定,则需要对组件的引用某种它会知道如何更新。这可以是一个进度条,它将是一个步骤,一个列表框或备注字段将接收一个带有状态更新的新行,一个标签控件的标题将被更新,等等。

答案 3 :(得分:0)

在长时间操作期间显示进度取决于几个因素(限制):

  • 定义/未定义的进度(你知道, 可以计算,有多少步骤 操作采取)
  • 中断/细分(你 将能够或必须中断 刷新进度的操作 给用户)
  • 操作是可线程的(你可以 把操作放到一个线程)

对于已定义的进度,通常会显示分段进度条,以及未定义的带有“Marquee”样式的动画或进度条。

主要考虑因素是操作是否分段/可中断。因为如果不是,并且您没有处理它,您的应用程序将冻结,直到操作完成。 搜索文件是分段操作的一个示例。每个找到的文件都是一个段,它使您能够向用户显示进度,并刷新显示。

示例:

TFrmUndefinedProgress = class(TForm)
private
   FCallbackProc           : TNotifyEvent;
protected
   procedure WndProc(var Message:TMessage); override;
public
   constructor Create(aCallbackProc: TNotifyEvent);
  procedure UpdateProgress(const aStr : string; aPercent : integer); 
...
constructor TFrmUndefinedProgress.Create(aCallbackProc: TNotifyEvent);
begin
   inherited Create(nil);
   FCallbackProc     := aCallbackProc;
end;
...
procedure TFrmUndefinedProgress.FormShow(Sender: TObject);
begin
   Update;
   PostMessage(Handle, WM_START_UNDEFPROG, 0, 0); 
end;

向表单的OnShow上的窗口过程发送消息,以确保它将首先呈现。

procedure TFrmUndefinedProgress.WndProc(var Message: TMessage);
begin
   if (Message.Msg = WM_START_UNDEFPROG) then begin
      if Assigned(FCallbackProc) then
         FCallbackProc(Self); --> Call your callback procedure
   PostMessage(Handle, WM_CLOSE, 0, 0); --> close when finished
   end
   else
   inherited;
end;

如果你在表单单元中进行常规程序......

procedure ShowUndefinedProgress(aCallbackProc : TNotifyEvent);
var
   FrmUndefinedProgress : TFrmUndefinedProgress;
begin
   FrmUndefinedProgress := nil;
   try
      FrmUndefinedProgress         := TFrmUndefinedProgress.Create(aCallbackProc);
      FrmUndefinedProgress.ShowModal;
   finally
      FreeAndNil(FrmUndefinedProgress);
   end;
end;

然后您可以调用这样的进度表:

ShowUndefinedProgress(HandleSomeOperation);

传递aCallbackProc的地方。 在你内部进行操作:

procedure TForm1.HandleSomeOperation(Sender: TForm);
var
   aProgress : TFrmUndefinedProgress;
begin
   --> Do something
   aProgress := TFrmUndefinedProgress(Sender);
   aProgress .UpdateProgress(SomeMessage, Percent);

更新每个找到的文件的显示...

如果您的操作需要很长时间,但是您无法打断它,那么您应该将它放在一个主题中。

  • 创建TThread对象的后代。
  • 覆盖它的执行方法
  • 在Execute中执行您的操作 并使用它:
  • 创建表单
  • 在OnShow上启动一些动画
  • 然后运行你的主题
  • 线程完成时关闭。