簡體   English   中英

Progressbar范圍和位置,如何在C ++中處理大數?

[英]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.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM