2

尝试实现 Windows Progressbar,以大数字字节显示下载进度,但无法正确执行。

对于 2.5gb 的下载,如果我执行以下操作,则下载完成后它会在完整范围内结束。

double dlSize = getDlSize();
unsigned int pbRange = (unsigned int)( dlSize / 3000 );
SendMessage( hProgressbar, PBM_SETRANGE, 0, MAKELPARAM( 0, pbRange ) );

然后在每个下载回调中设置新位置:

double dlBytes = bytesDownloaded();
unsigned int newIncrement = (unsigned int)( dlBytes / 3000 );
SendMessage( hProgressbar, PBM_DELTAPOS, (WPARAM)newIncrement, 0 );

这是一个非常愚蠢的实现,我不想陷入 xy 的情况,所以我的问题是什么是正确的方法来实现一个以 2-5GB 为单位的大数字的进度条?


我尝试了@msandiford 和@NikBougalis 下面建议的两种方法,通过考虑进度条的宽度并使用百分比而不是实际数字,我什至将两者结合起来,但在所有情况下,newIncrement 总是出现 0,也许那是因为dlSize 总是较低(在 double newIncrement 中出现类似 1.15743e+007 的内容,类型转换它和它的 0 )。

我还能做什么?

结合两种方法的新代码:

编辑 2: 对代码添加了一些检查,因为我不断为 newIncrement 获得 0,看起来它现在可以工作,不确定效果如何:

GetClientRect(hProgressbar, &pbRCClient);
pbWidth = pbRCClient.right - pbRCClient.left; // (pbWidth  its a global variable)
unsigned int pbRange = pbRCClient.right - pbRCClient.left;
SendMessage( hProgressbar, PBM_SETRANGE, 0, MAKELPARAM( 0, pbRange ) );

并在更新时:

double dlSize = getDlSize();
double doubleIncrement = ( ( dlSize * pbWidth ) / totalSize );

unsigned int newIncrement;

if ( (unsigned int)doubleIncrement < 1 )
{
    blockFill += doubleIncrement;

    if ( (unsigned int)blockFill > 1 )
    {
        newIncrement = ( unsigned int )blockFill;
        SendMessage( hProgressbar, PBM_DELTAPOS, (WPARAM)newIncrement, 0 );
        blockFill = 0;
    }
}
else
{
    newIncrement = ( unsigned int )( doubleIncrement );
    SendMessage( hProgressbar, PBM_DELTAPOS, (WPARAM)newIncrement, 0 );
    //blockFill = 0;
}

编辑3:看起来它仍然很早就完成了。

4

2 回答 2

3

您遇到的最大问题是进度条控件本身的限制。PBM_SETRANGE 是有限的,尽管如果您需要处理大于 2GB 的值,您可以使用PBM_SETRANGE32 ,但您仍然会遇到问题。

巧合的是,为什么要使用双精度?使用 UINT64,其最大容量约为 16,384 PB(如果您下载的内容会溢出...跳过进度条,只会让您和您的客户感到沮丧)。整数对于计算字节之类的东西非常有效。

如果您知道正在下载的文件的完整大小,解决具有有限最大范围的进度条大小的一种方法是使进度条从 0 开始并以 100 结束。然后您可以转换使用简单的三规则将接收到的字节分成百分比:

percent = (bytes_received * 100) / max_bytes;

如果您想获得更多的“粒度”,可以将进度条的比例更改为 1000,并相应地调整计算;您甚至可以达到 10000,但此时根据控件的宽度(或高度),您可能会遇到显示器的分辨率。

于 2012-12-22T07:19:36.187 回答
2

使进度条比进度条窗口本身的像素数更准确可能没有什么意义。基于此,您应该能够很容易地将目标缩放到像素数。

    RECT rcClient;
    GetClientRect(hProgressBar, &rcClient);
    unsigned int pbRange = rcClient.right - rcClient.left;

    // Need to either keep unitsPerPixel, or recalculate later
    double pixelsPerUnit = pbRange / dlSize;
    SendMessage(hProgressBar, PBM_SETRANGE, 0, MAKELPARAM(0, pbRange));

然后更新进度将类似于:

    double dlBytes = totalBytesDownloaded();
    unsigned int newProgress = (unsigned int)(dlBytes * pixelsPerUnit);
    SendMessage(hProgressBar, PBM_SETPOS, (WPARAM)newProgress, 0);

如果进度窗口可以以某种方式调整大小,则需要重新计算pbRange,重置进度条范围并重新计算unitsPerPixel以响应WM_SIZE消息。

于 2012-12-22T07:15:58.730 回答