93

大きなファイルをダウンロードするためにC++でコンソールプログラムを書いています。ファイルサイズがわかっているので、作業スレッドを開始してダウンロードします。見栄えを良くするために進行状況インジケーターを表示したいと思います。

coutまたはprintfで、異なる時間に同じ位置に異なる文字列を表示するにはどうすればよいですか?

4

9 に答える 9

118

出力の幅が固定されている場合は、次のようなものを使用します。

float progress = 0.0;
while (progress < 1.0) {
    int barWidth = 70;

    std::cout << "[";
    int pos = barWidth * progress;
    for (int i = 0; i < barWidth; ++i) {
        if (i < pos) std::cout << "=";
        else if (i == pos) std::cout << ">";
        else std::cout << " ";
    }
    std::cout << "] " << int(progress * 100.0) << " %\r";
    std::cout.flush();

    progress += 0.16; // for demonstration only
}
std::cout << std::endl;

http://ideone.com/Yg8NKj

[>                                                                     ] 0 %
[===========>                                                          ] 15 %
[======================>                                               ] 31 %
[=================================>                                    ] 47 %
[============================================>                         ] 63 %
[========================================================>             ] 80 %
[===================================================================>  ] 96 %

この出力は1行下に表示されますが、ターミナルエミュレーター(Windowsコマンドラインでもそうだと思います)では同じ行に出力されることに注意してください。

最後に、さらに多くのものを印刷する前に、改行を印刷することを忘れないでください。

最後のバーを削除したい場合は、たとえばのように短いものを印刷するために、スペースで上書きする必要があります"Done."

また、もちろんprintfCでも同じことができます。上記のコードを適応させるのは簡単です。

于 2013-01-26T18:11:11.070 に答える
61

改行(\ n)なしで「キャリッジリターン」(\ r)を使用でき、コンソールが正しい動作をすることを期待します。

于 2013-01-26T18:05:55.227 に答える
55

プログレスバーの幅を調整できるCソリューションの場合は、次を使用できます。

#define PBSTR "||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||"
#define PBWIDTH 60

void printProgress(double percentage) {
    int val = (int) (percentage * 100);
    int lpad = (int) (percentage * PBWIDTH);
    int rpad = PBWIDTH - lpad;
    printf("\r%3d%% [%.*s%*s]", val, lpad, PBSTR, rpad, "");
    fflush(stdout);
}

次のように出力されます。

 75% [||||||||||||||||||||||||||||||||||||||||||               ]
于 2016-03-30T17:33:36.927 に答える
14

ブーストprogress_displayを見てください

http://www.boost.org/doc/libs/1_52_0/libs/timer/doc/original_timer.html#Class%20progress_display

私はそれがあなたが必要とすることをするかもしれないと思います、そして私はそれがヘッダーのみのライブラリであると信じているのでリンクするものは何もありません

于 2013-01-26T21:28:05.917 に答える
12

キャリッジリターン文字(\r)を印刷して、出力「カーソル」を現在の行の先頭に戻すことができます。

より洗練されたアプローチについては、ncurses(コンソールのテキストベースのインターフェイス用のAPI)のようなものを見てください。

于 2013-01-26T18:05:41.957 に答える
6

私はこの質問に答えるのが少し遅れていることを知っていますが、私はあなたが望むことを正確に行う簡単なクラスを作りました。(私がこの前に書いたことを覚えておいてusing namespace std;ください。):

class pBar {
public:
    void update(double newProgress) {
        currentProgress += newProgress;
        amountOfFiller = (int)((currentProgress / neededProgress)*(double)pBarLength);
    }
    void print() {
        currUpdateVal %= pBarUpdater.length();
        cout << "\r" //Bring cursor to start of line
            << firstPartOfpBar; //Print out first part of pBar
        for (int a = 0; a < amountOfFiller; a++) { //Print out current progress
            cout << pBarFiller;
        }
        cout << pBarUpdater[currUpdateVal];
        for (int b = 0; b < pBarLength - amountOfFiller; b++) { //Print out spaces
            cout << " ";
        }
        cout << lastPartOfpBar //Print out last part of progress bar
            << " (" << (int)(100*(currentProgress/neededProgress)) << "%)" //This just prints out the percent
            << flush;
        currUpdateVal += 1;
    }
    std::string firstPartOfpBar = "[", //Change these at will (that is why I made them public)
        lastPartOfpBar = "]",
        pBarFiller = "|",
        pBarUpdater = "/-\\|";
private:
    int amountOfFiller,
        pBarLength = 50, //I would recommend NOT changing this
        currUpdateVal = 0; //Do not change
    double currentProgress = 0, //Do not change
        neededProgress = 100; //I would recommend NOT changing this
};

使用方法の例:

int main() {
    //Setup:
    pBar bar;
    //Main loop:
    for (int i = 0; i < 100; i++) { //This can be any loop, but I just made this as an example
        //Update pBar:
        bar.update(1); //How much new progress was added (only needed when new progress was added)
        //Print pBar:
        bar.print(); //This should be called more frequently than it is in this demo (you'll have to see what looks best for your program)
        sleep(1);
    }
    cout << endl;
    return 0;
}

注:バーの外観を簡単に変更できるように、すべてのクラスの文字列を公開しました。

于 2016-03-20T19:42:30.820 に答える
5

別の方法として、「ドット」または任意の文字を表示することができます。次のコードは、進行状況インジケーター[読み込みの種類...]を1秒ごとにドットとして出力します。

PS:私はここで睡眠を使用しています。パフォーマンスが懸念される場合は、よく考えてください。

#include<iostream>
using namespace std;
int main()
{
    int count = 0;
    cout << "Will load in 10 Sec " << endl << "Loading ";
    for(count;count < 10; ++count){
        cout << ". " ;
        fflush(stdout);
        sleep(1);
    }
    cout << endl << "Done" <<endl;
    return 0;
}
于 2015-02-27T14:00:20.857 に答える
2

これが私が作った簡単なものです:

#include <iostream>
#include <windows.h>

using namespace std;

int barl = 20;

int main() {
   system("color 0e");  
   cout << "[";     
   for (int i = 0; i < barl; i++) {         
      Sleep(100);       
      cout << ":";  
   }
   cout << "]";
}
于 2017-12-24T10:30:54.510 に答える
0

このコードがあなたを助けるかもしれません-

#include <iostream>
#include <string>
#include <thread>
#include <chrono>
#include <cmath>

using namespace std;

void show_progress_bar(int time, const std::string &message, char symbol)
{
    std::string progress_bar;
    const double progress_level = 1.42;

    std::cout << message << "\n\n";

    for (double percentage = 0; percentage <= 100; percentage += progress_level)
    {
        progress_bar.insert(0, 1, symbol);
        std::cout << "\r [" << std::ceil(percentage) << '%' << "] " << progress_bar;
        std::this_thread::sleep_for(std::chrono::milliseconds(time));       
    }
    std::cout << "\n\n";
}

int main()
{
    show_progress_bar(100, "progress" , '#');
}
于 2021-08-01T17:36:31.767 に答える