【问题标题】:Progress Bar design patterns?进度条设计模式?
【发布时间】:2010-03-24 09:35:22
【问题描述】:

我正在编写的应用程序执行长度算法,通常需要几分钟才能完成。在此期间,我想向用户显示一个进度条,它会尽可能精确地指示算法完成了多少。

该算法分为几个步骤,每个步骤都有自己的典型时序。例如 -

  • 初始化(500 毫秒)
  • 读取输入(5 秒)
  • 第 1 步(30 秒)
  • 第 2 步(3 分钟)
  • 写入输出(7 秒)
  • 正在关闭(10 毫秒)

通过设置其工作范围,例如 [0 到 150],然后报告其在主循环中完成的值,每个步骤都可以很容易地报告其进度。

我目前设置的是嵌套进度监视器方案,它形成了一种隐式的进度报告树。

所有进度监视器都继承自一个接口IProgressMonitor

class IProgressMonitor
{
public:
  void setRange(int from, int to) = 0;
  void setValue(int v) = 0;
};

树的根是 ProgressMonitor,它连接到实际的 GUI 界面:

class GUIBarProgressMonitor : public IProgressMonitor
{
   GUIBarProgressMonitor(ProgressBarWidget *);
};

树中的任何其他节点都是监控父进程的一部分:

class SubProgressMonitor : public IProgressMonitor
{
  SubProgressMonitor(IProgressMonitor *parent, int parentFrom, int parentLength)
  ...
};

SubProgressMonitor 控制其父级的[parentFrom, parentFrom+parentLength] 范围。

使用此方案,我可以根据全局时序中每个步骤的预期相对部分静态划分顶级进度。然后可以将每个步骤进一步细分为碎片等'

这样做的主要缺点是除法是静态的,根据运行时发现的变量进行更改会很痛苦。

那么问题是:是否有任何已知的进度监控设计模式可以解决这个问题?

【问题讨论】:

    标签: design-patterns oop progress-bar


    【解决方案1】:

    一个非常有趣的方法是用户感知。

    Chris Harrison 发表了一篇关于用户如何根据进度条报告的进度感知时间流逝的论文(尽管在所有实验中实际持续时间明显相同)

    请注意,首选显示公式是 (x + (1-x) / 2 )8 其中x 是 0 到 1 的实际进度:)

    因此,我会建议:

    • 收集有关给定任务所用时间百分比的一些统计数据
    • 测量初始化并使用它来缩放进度条上的进度,保持悲观态度(例如准备 10-15% 的缓冲区)
    • 就在最后一个任务之前(或最后几个任务,只要它们具有确定的持续时间),全力以赴,以便及时完成进度条(渐进式加速)

    我知道,这不准确,但如果用户认为它更快,我会接受它!

    【讨论】:

      【解决方案2】:

      Péter 是我在一个大型项目中采用的方法;在我们的试点和初始部署期间,我们成千上万的移动设备中的每一个都在发回时间和使用数据,我们使用时间的平均值、中值和标准差来微调我们的任务配置(当任务被允许运行,允许运行多长时间,进度条显示中使用了哪些值等)。由于我们的解决方案有点像您的解决方案,但由 XML 配置文件中提供的值驱动,我们考虑将其构建为一个自动化系统(例如,服务器会每隔一段时间检查这些值,请注意最近某些任务需要更长的时间比他们过去的几天,并更新配置文件以重新安排或延长它们),但认为仅仅为了防止每隔几周进行一次快速人工审查是不值得的。

      由于我不知道您的问题的技术解决方案,我认为您向用户展示的内容(以及您花费多少时间开发解决方案)应该基于功能问题:谁在使用它?信息需要多准确?这是一个交互式过程,在此过程中他们不能做其他工作,还是可以让它在后台运行并返回?您的长期运行功能发生的工作流程是时间敏感型还是任务关键型?

      很抱歉,我实际上无法为您提供您正在寻找的答案,但也许粗略地考虑一下您想要实现的目标是一个好主意。 = )

      【讨论】:

        【解决方案3】:

        构建一个 AggregateProgressMonitor,它会根据子进度监视器报告的信息自动计算子进度划分。子进度监视器应至少通知父“预期”运行时间。然后,子监视器的估计运行时间可以通过它们各自的操作根据运行时参数进行更新,并且整体进度报告将相应地自动调整。

        这样的……

        class IAggregateProgressMonitor : public IProgressMonitor
        {
           void setChildValue(IProgressMonitor *, int v);
           void setChildEstimatedTime(IProgressMonitor *, int v);
        }
        
        class AggregateProgressMonitor : public IAggregateProgressMonitor 
        {
           void setChildValue(IProgressMonitor * child, int v)
           {
              int aggregateValue = mapChildValueToAggregateValue(child, v);
              setValue(aggregateValue);
           }
        
           void setChildEstimatedTime(IProgressMonitor * child, ulong ms)
           {
              children[child]->estimatedTime = ms;
              updateChildProgressRatios();
           }
        }
        
        class SubProgressMonitor : public IProgressMonitor
        {
          SubProgressMonitor(IAggregateProgressMonitor *parent, int parentFrom, 
                             int parentLength) ... ;
          void setValue(int v)
          {
             parent->setChildValue(this, v);
          }
        
          void setEstimatedRunningTime(ulong ms)
          {
            parent->setChildEstimatedTime(this, ms);
          } 
        };
        

        您甚至可以使用观察到的第一步的时间来重新映射后续进度报告器,使其更加准确。

        您需要在 AggregateProgressMonitor 中保留某种有序地图,以便能够跟踪和计算来自孩子的所有信息。

        完成后,您可以扩展 AggregateProgressMonitor(覆盖 IProgressMonitor 方法)以向用户显示进度。

        【讨论】:

          【解决方案4】:

          这是一个棘手的问题,我们在之前的项目中也遇到过。

          我能想到的最好办法是收集每个阶段在现实生活中实际需要多长时间的统计数据,并相应地调整相对间隔长度。

          我们还没有在那个项目中实现它(至少只要我在那里),所以这只是一个理论上的想法:-)

          【讨论】:

            【解决方案5】:

            您可以考虑将进度条替换为进度圈。如果任务有 N 个步骤,则在饼图中制作 N 个楔形,并在该步骤运行时像进度条一样填充每个楔形。

            作为附加步骤,可能会为每个步骤显示一些文本,以便在步骤进行时有一些内容可供阅读。

            【讨论】:

            • 投了反对票,因为答案侧重于可视化,但问题是关于代码中的设计模式。该操作显然远远超出了对不同长度的步骤使用相等部分的进度的简单解决方案。
            猜你喜欢
            • 2014-06-17
            • 2016-08-18
            • 2021-08-31
            • 1970-01-01
            • 1970-01-01
            • 2011-09-10
            • 2013-09-26
            • 2020-01-25
            相关资源
            最近更新 更多