[英]Progressbar Range and position, how to handle big numbers in C++?
嘗試實現Windows進度條,以大數字字節顯示下載進度,但無法正確執行。
如果執行以下操作,則對於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:看起來它仍在早期完成。
您遇到的最大問題是進度條控件本身的局限性。 PBM_SETRANGE受限制,盡管如果需要處理大於2GB的值,則可以使用PBM_SETRANGE32 ,但仍然會遇到問題。
巧合的是,為什么要雙重使用呢? 使用UINT64,其最大容量約為16,384 PB(如果您正在下載的內容可能會溢出……請跳過進度欄,它只會使您和您的客戶感到沮喪)。 整數可以很好地用於計數字節之類的東西。
如果您知道要下載的文件的完整大小,一種解決進度條的最大范圍受限制的大小的方法是使進度條從0開始到100結束。然后,您可以轉換使用三個簡單規則將收到的字節分成一個百分比:
percent = (bytes_received * 100) / max_bytes;
如果要獲得更多的“粒度”,可以將進度條的比例更改為1000,並相應地調整計算;例如, 您甚至可以設置為10000,但在那時,根據控件的寬度(或高度),您可能會遇到監視器分辨率的問題。
使進度條比進度條窗口本身中的像素數更准確可能沒有什么意義。 基於此,您應該能夠輕松地將目標縮放到像素數。
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
消息。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.