순수 C / C ++ (cout / printf)에서 진행률 표시기를 표시하는 방법은 무엇입니까?


81

큰 파일을 다운로드하기 위해 C ++로 콘솔 프로그램을 작성하고 있습니다. 파일 크기를 알고 있으며 작업 스레드를 시작하여 다운로드합니다. 더 멋지게 보이도록 진행률 표시기를 표시하고 싶습니다.

cout 또는 printf에서 다른 시간에 동일한 위치에 다른 문자열을 표시하는 방법은 무엇입니까?


2
PDCurses에게 라이브러리 체크 아웃 pdcurses.sourceforge.net을
Lefteris

2
C ++ 콘솔 진행률 표시기 가 도움이 될 수 있습니다
David L.

2
산란 wget과정은 옵션이 아니다?
Alexandre C.


답변:


56

줄 바꿈 (\ n)없이 "캐리지 리턴"(\ r)을 사용할 수 있으며 콘솔이 올바른 작업을 수행하기를 바랍니다.


31
+ 수동 플러시, 그렇지 않으면 출력이 버퍼링되기 때문에 즉시 표시되지 않습니다.
leemes

그리고 사용자가 실수로 Enter 키를 누르면 다음과 같이 분류됩니다. (그 외에는 아마도 가장 휴대 성이 뛰어난 솔루션 일 것입니다. +1.
Ali

@Ali 것을 방지하기 위해, 당신은 (참조 해제 에코 할 것이다 man termios)
leemes

1
@leemes #include <termios.h>, M $ Windows에서 시도해보세요. :) 어쨌든, 팁 주셔서 감사합니다. 아마 Linux에서 시도해 볼 것입니다.
알리

1
@Ali W1ndOw $에 해당하는 것이있을 수 있지만 모르겠습니다. ;)
leemes 2013 년

108

출력의 고정 너비로 ​​다음과 같이 사용하십시오.

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 %

이 출력은 서로 아래에 한 줄로 표시 되지만 터미널 에뮬레이터 (Windows 명령 줄에서도 동일)에서는 동일한 줄에 인쇄 됩니다 .

마지막에 더 많은 것을 인쇄하기 전에 개행을 인쇄하는 것을 잊지 마십시오.

끝에서 막대를 제거하려면 공백으로 덮어 써야합니다 "Done.". 예를 들어 .

물론 printfC 에서도 동일한 작업을 수행 할 수 있습니다 . 위의 코드를 수정하는 것은 간단해야합니다.


37

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% [||||||||||||||||||||||||||||||||||||||||||               ]

조심하세요, ';'첫 번째 끝에는 없어야합니다 #define!
Robb1

3
이것은 내가 지금까지 찾은 가장 간단하고 최상의 솔루션입니다
horro

대신 ASCII 문자를 표시하는 방법이 있습니까 | ? 감사합니다
momo123


10

캐리지 리턴 문자 ( \r)를 인쇄 하여 출력 "커서"를 현재 행의 처음으로 다시 이동할 수 있습니다 .

보다 정교한 접근 방식을 위해 ncurses (콘솔 텍스트 기반 인터페이스 용 API)와 같은 것을 살펴보십시오.


4
+ 수동 플러시, 그렇지 않으면 출력이 버퍼링되기 때문에 즉시 표시되지 않습니다.
leemes

3
+ '\b'커서를 한 위치 왼쪽으로 이동합니다.
Alexey Frunze 2013 년

1
ncurses의 경우 +1. 좀 더 복잡한 것을하고 싶다면 확실히 갈 길입니다.
Leo

4

이 질문에 답하는 데 조금 늦었지만 원하는 것을 정확하게 수행하는 간단한 수업을 만들었습니다 . ( 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;
}

참고 : 바의 모양을 쉽게 변경할 수 있도록 모든 클래스의 문자열을 공개했습니다.


3

또 다른 방법은 "점"또는 원하는 문자를 표시하는 것입니다. 아래 코드는 1 초 후에 진행률 표시기 [일종의 로딩 ...]를 점으로 인쇄합니다.

추신 : 저는 여기서 수면을 사용하고 있습니다. 성능이 문제라면 두 번 생각하십시오.

#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;
}

1

다음은 내가 만든 간단한 것입니다.

#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 << "]";
}
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.