You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在WizardForm.PreparingPage显示跑马灯进度条并判断结束时机?

解决Inno Setup准备阶段跑马灯进度条的时机控制问题

问题根源分析

你当前的代码存在两个核心问题:

  1. 用固定时长的while+Sleep循环会阻塞UI主线程,导致Setup本身的准备工作(如临时文件提取、系统检查)无法正常推进,同时用户操作也会失去响应。
  2. 固定时长完全无法匹配实际的准备耗时,必然出现提前关闭或超时显示的情况。

下面提供两种可行的解决方案,优先推荐第一种最简单的实现:


方案一:直接修改原生准备页的进度条样式

不需要额外创建页面,直接将系统自带的PreparingPage进度条改为跑马灯样式,Setup会自动控制页面的显示和隐藏(准备完成后自动跳转下一页):

[Code]
procedure InitializeWizard;
begin
  // 将原生准备页的进度条设置为跑马灯模式
  WizardForm.PreparingPage.ProgressBar.Style := pbstMarquee;
  // 可选:设置跑马灯滚动速度(单位:毫秒,值越小滚动越快)
  WizardForm.PreparingPage.ProgressBar.MarqueeAnimationSpeed := 50;
end;

这种方式完全不需要手动处理时机,Setup的原生逻辑会自动完成页面生命周期管理,是最省心的方案。


方案二:自定义跑马灯进度页并自动跟随准备阶段生命周期

如果需要自定义页面内容(比如修改标题、提示文本),可以用TOutputMarqueeProgressPage替代原生页面,通过定时器维持动画,并监听页面切换事件控制显示/隐藏:

步骤1:声明必要的API和全局变量

[Code]
const
  WM_TIMER = $0113;

var
  ProgressPage: TOutputMarqueeProgressPage;
  TimerID: LongWord;

// 导入Windows定时器API
function SetTimer(hWnd: HWND; nIDEvent, uElapse: UINT; lpTimerFunc: TFNTimerProc): UINT;
  external 'SetTimer@user32.dll stdcall';

function KillTimer(hWnd: HWND; uIDEvent: UINT): BOOL;
  external 'KillTimer@user32.dll stdcall';

// 定时器回调:维持跑马灯动画
procedure TimerProc(hWnd: HWND; uMsg: UINT; idEvent: UINT_PTR; dwTime: DWORD);
begin
  if Assigned(ProgressPage) then
    ProgressPage.Animate;
end;

步骤2:初始化自定义页面和定时器

procedure InitializeWizard;
begin
  // 创建自定义跑马灯进度页
  ProgressPage := CreateOutputMarqueeProgressPage(
    '准备安装...', 
    '正在完成安装前的准备工作,请稍候...'
  );
  // 隐藏原生准备页
  WizardForm.PreparingPage.Visible := False;
  // 设置定时器,每50ms触发一次动画刷新
  TimerID := SetTimer(0, 0, 50, @TimerProc);
end;

步骤3:监听页面切换事件控制进度页

procedure CurPageChanged(CurPageID: Integer);
begin
  // 进入准备阶段时显示自定义页面
  if CurPageID = wpPreparing then
  begin
    ProgressPage.Show;
  end
  // 离开准备阶段时关闭定时器并释放页面资源
  else if Assigned(ProgressPage) then
  begin
    if TimerID <> 0 then
    begin
      KillTimer(0, TimerID);
      TimerID := 0;
    end;
    ProgressPage.Hide;
    ProgressPage.Free;
    ProgressPage := nil;
  end;
end;

步骤4:处理中途取消安装的情况

function SetupCancel(): Boolean;
begin
  // 清理定时器和页面资源
  if TimerID <> 0 then
  begin
    KillTimer(0, TimerID);
    TimerID := 0;
  end;
  if Assigned(ProgressPage) then
  begin
    ProgressPage.Free;
    ProgressPage := nil;
  end;
  Result := True;
end;

这种方式不会阻塞主线程,Setup可以正常完成准备工作,当准备阶段结束时,Setup会自动跳转到下一页,CurPageChanged事件会捕获到页面切换动作,从而正确关闭自定义进度页。

内容的提问来源于stack exchange,提问作者iTz_ElKay

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.12 08:03:15