TResourceStream的进度条(Delphi)

3

如何在SaveToFile方法中使用进度条?实际上,我想将资源保存到文件中,并在保存时将进度条从0%更新到100%,我该怎么做?


我认为我应该使用MemoryStream,但我不知道如何实现。 - Kermia
你能告诉我什么是一个真正的问题吗? - Kermia
你不能将 ProgressBar 与 TResourceStream.SaveToFile 方法一起使用。但是当然可以使用 ProgressBar 可视化保存资源到文件中。 - kludg
3
更好的提问方式是:“我想将内容保存到文件中,并在保存过程中从0%更新进度条到100%,我该如何实现?”任何少于10个单词的问题几乎都是糟糕的问题。(如何使用某某进行某某操作?:糟糕的问题) - Warren P
2个回答

6
您可以像下面的代码一样制作自己的TResourceStream派生类。但是对于大型资源(这很可能是情况,否则您不必看到进度),最好将其“包装”在单独的线程中。如果需要帮助,请告诉我。
type
  TForm1 = class(TForm)
    Button: TButton;
    ProgressBar: TProgressBar;
    procedure ButtonClick(Sender: TObject);
  private
    procedure StreamProgress(Sender: TObject; Percentage: Single);
  end;

var
  Form1: TForm1;

implementation

{$R *.dfm}

type
  TStreamProgressEvent = procedure(Sender: TObject;
    Percentage: Single) of object;

  TProgressResourceStream = class(TResourceStream)
  private
    FOnProgress: TStreamProgressEvent;
  public
    procedure SaveToFile(const FileName: TFileName);
    property OnProgress: TStreamProgressEvent read FOnProgress
      write FOnProgress;
  end;

{ TProgressResourceStream }

procedure TProgressResourceStream.SaveToFile(const FileName: TFileName);
var
  Count: Int64;
  Stream: TStream;
  BlockSize: Int64;
  P: PAnsiChar;
  WriteCount: Int64;
begin
  if Assigned(FOnProgress) then
  begin
    Count := Size;
    if Count <> 0 then
    begin
      Stream := TFileStream.Create(FileName, fmCreate);
      try
        if Count < 500 then
          BlockSize := 5
        else
          BlockSize := Count div 50;
        P := Memory;
        WriteCount := 0;
        while WriteCount < Count do
        begin
          if WriteCount < Count - BlockSize then
            Inc(WriteCount, Stream.Write(P^, BlockSize))
          else
            Inc(WriteCount, Stream.Write(P^, Count - WriteCount));
          Inc(P, BlockSize);
          FOnProgress(Self, WriteCount / Count);
        end;
      finally
        Stream.Free;
      end;
    end;
  end
  else
    inherited SaveToFile(FileName);
end;

{ TForm1 }

procedure TForm1.ButtonClick(Sender: TObject);
var
  Stream: TProgressResourceStream;
begin
  ProgressBar.Min := 0;
  Stream := TProgressResourceStream.Create(HInstance, 'TFORM1', RT_RCDATA);
  try
    Stream.OnProgress := StreamProgress;
    Stream.SaveToFile('TForm1.dat');
  finally
    Stream.Free;
  end;
end;

procedure TForm1.StreamProgress(Sender: TObject; Percentage: Single);
begin
  with ProgressBar do
    Position := Round(Percentage * Max);
end;

这对我来说有点复杂。 - Kermia
这段代码不起作用。当我提取文件时,它会损坏。 - Kermia
啊,明白了。恐怕这就是TResourceStream的工作方式。要检查代码是否正确:将此文件与标准SaveToFile例程生成的文件进行比较。 - NGLN
Unicode Delphi版本?您可以尝试将P: PChar;更改为P: PAnsiChar;吗? - NGLN
1
代码行数并不是公平比较的良好标准。尝试进行分析:你会发现没有区别。 - NGLN
显示剩余4条评论

4

由于它继承自TStream,因此您可以使用Size属性获取总大小,并使用Position获取当前位置。您可以使用这些来“驱动”进度条。然后,您不会使用SaveToFile来写入文件,而是使用单独的TFileStream,并从TResourceStream按块写入它。您可以使用TStream.CopyFrom方法进行最后一部分。


1
但是他没有使用CopyFrom方法。 - Kermia

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接