尝试实现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 );
这是一个非常noobish的实现,我不希望陷入xy的情况,所以我的问题是实现一个大数字的进度条的正确方法是什么,以2-5GB的字节为单位?
我尝试了下面由@msandiford和@NikBougalis提出的两种方法,通过考虑进度条的宽度和使用百分比而不是实际数字,我甚至将两者结合起来,但在所有情况下,newIncrement总是出现0,也许那是因为dlSize总是更低(在new 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:看起来它还在提前结束。
答案 0 :(得分:3)
您遇到的最大问题是进度条控件本身的限制。 PBM_SETRANGE是有限的,虽然你可以使用PBM_SETRANGE32如果你需要处理大于2GB的值,你仍然会遇到问题。
巧合的是,为什么要使用双人?使用UINT64,其最大值大约为16,384PB(如果您正在下载会溢出的东西......请跳过进度条,它只会让您和您的客户感到压抑)。整数非常适合计算像字节这样的东西。
如果您知道要下载的文件的完整大小,那么解决具有有限最大范围的进度条大小的一种方法是使进度条从0开始并以100结束。您可以使用simple rule of three:
将收到的字节转换为百分比percent = (bytes_received * 100) / max_bytes;
如果您希望获得更多“粒度”,可以将进度条的比例更改为1000并相应地调整计算;您甚至可以转到10000但在此时根据控件的宽度(或高度),您可能会遇到显示器的分辨率。
答案 1 :(得分: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
消息。