如何为IdHTTP实现的文件下载功能添加TProgressBar进度条
解决方案
1 解决类型识别报错问题
你遇到的TWorkMode无法识别的问题是因为缺少Indy的核心单元引用,只需要在当前单元的uses段添加IdGlobal即可,无需修改IdHTTP的源码。
2 实现进度更新相关事件方法
需要为IdHTTP组件绑定3个事件来处理进度状态:
OnWorkBegin:下载启动时触发,用于初始化进度条OnWork:下载过程中持续触发,用于更新当前进度OnWorkEnd:下载结束时触发,用于重置进度条状态
事件代码示例
// 下载开始事件 procedure T你的Form类名.IdHTTP1WorkBegin(Sender: TObject; AWorkMode: TWorkMode; AWorkCountMax: Int64); begin // 仅处理下载(读)操作的事件 if AWorkMode <> wmRead then Exit; ProgressBar1.Visible := True; ProgressBar1.Position := 0; // 服务器返回了文件总大小则用真实值,否则设置为100做假进度 ProgressBar1.Max := IfThen(AWorkCountMax > 0, AWorkCountMax, 100); end; // 下载进度更新事件 procedure T你的Form类名.IdHTTP1Work(Sender: TObject; AWorkMode: TWorkMode; AWorkCount: Int64); begin if AWorkMode <> wmRead then Exit; if ProgressBar1.Max = 100 then // 无总大小的情况累加假进度 ProgressBar1.Position := IfThen(ProgressBar1.Position < 99, ProgressBar1.Position + 1, 50) else // 有总大小则用真实进度 ProgressBar1.Position := AWorkCount; // 如果下载逻辑在主线程执行,加这句可以避免界面卡死 Application.ProcessMessages; end; // 下载结束事件 procedure T你的Form类名.IdHTTP1WorkEnd(Sender: TObject; AWorkMode: TWorkMode); begin if AWorkMode <> wmRead then Exit; ProgressBar1.Position := 0; ProgressBar1.Visible := False; end;
3 修改原下载代码绑定事件
在创建IdHTTP实例后添加事件绑定逻辑即可:
Url := filetodownloadvar; IdHTTP1 := TIdHTTP.Create(Self); Stream := TMemoryStream.Create; try // 新增:绑定进度事件 IdHTTP1.OnWorkBegin := IdHTTP1WorkBegin; IdHTTP1.OnWork := IdHTTP1Work; IdHTTP1.OnWorkEnd := IdHTTP1WorkEnd; // 可选:开启自动重定向支持 IdHTTP1.HandleRedirects := True; IdHTTP1.Get(Url, Stream); Stream.SaveToFile(FileName); finally Stream.Free; IdHTTP1.Free; end;
注意事项
- 如果下载逻辑放在子线程中执行,不能直接操作
ProgressBar1控件,需要通过TThread.Synchronize将更新操作同步到主线程执行 - 部分服务器不会返回
Content-Length响应头,这种情况下无法获取文件总大小,你可以选择提前发起HEAD请求获取文件大小,或者使用滚动样式的进度条代替百分比进度
内容的提问来源于stack exchange,提问作者Codrut
相关产品推荐
相关产品推荐

