Версия для печати темы
Нажмите сюда для просмотра этой темы в оригинальном формате
Форум программистов > C/C++: Для новичков > Прогресс бар в консоле


Автор: Ak47black 4.3.2010, 20:56
Здравствуйте.
Делаю консольную программу(клиент сервер), которая пересылает файл.
Хочу сделать прогресс бар как-нибудь в консоле, но что-бы не сильно грузил процессор.
Думаю сделать, чтобы что-бы он обновлялся только в тех случаях когда он будет менять свой облик.
Зависимость у него хочу сделать - число пересланных бит от общего размера файла.
Хотел-бы узнать как тут грамотней сделать?
Какие функции можно применить?
Я в работе с консолями мало что знаю. Кроме как на подобии printf, cout, ...

Автор: UniBomb 4.3.2010, 21:19
Ak47black, выбираешь какой-нибудь символ, определяешь длину шкалы и с соответствующим дискретным шагом выводиш в строку выбранный символ.

Например ты выбрал символ ▓ и 10 символов весь прогрессбар.  каждый раз, когда ты получил 10% данных ты выводишь обычным printf (или через cout если ты на С++ пишешь) этот символ.

Обычно в досе под это дело используют вот эти символы:

Цитата

░ ▒ ▓


А там уже извращайся наводи эстетику как тебе вздумается.

Второй вариант - выводить в одной и той же знаковой позиции по очереди символы "/", "-", "|", "\" а после них число процентов от принятого файла. Получается эффект вращающейся палочки, символизирующей что процесс идёт и программа не зависла.

Автор: andrew_121 4.3.2010, 21:40
user posted image
такой?

вот.
Код

#include <iostream>
#include <string>
#include <unistd.h>

class console_progress_bar {
public:
    explicit console_progress_bar(int expected_count,
                             std::ostream& os,
                             const std::string& s1 = "\n",
                             const std::string& s2 = "",
                             const std::string& s3 = "" )
   : _stream(os), _str1(s1), _str2(s2), _str3(s3) {
      restart(expected_count);
   }
    ~console_progress_bar() {}

   void restart(int expected_count) {
      _count = _next_tic_count = _tic = 0;
      _expected_count = expected_count;

      _stream  << _str1 << "0%   10   20   30   40   50   60   70   80   90   100%\n"
               << _str2 << "|----|----|----|----|----|----|----|----|----|----|"
               << std::endl  << _str3;
      if ( !_expected_count )
         _expected_count = 1;
   }
   int operator+=(int increment) {
      if ( (_count += increment) >= _next_tic_count ) {
         display_tic();
      }
      return _count;
   }

   int operator++()           { return operator+=( 1 ); }
   int count() const          { return _count; }
   int expected_count() const { return _expected_count; }
private:
   std::ostream& _stream;
   const std::string  _str1;
   const std::string  _str2;
   const std::string  _str3;
   int _count;
   int _expected_count;
   int _next_tic_count;
   int _tic;
    /**/
   void display_tic() {
      int tics_needed = static_cast<int>( (static_cast<double>(_count)/_expected_count)*50.0 );
      do {
         _stream << "*";
         _stream.flush();
      } while ( ++_tic < tics_needed );
      _next_tic_count = static_cast<int>((_tic/50.0)*_expected_count);
      if ( _count == _expected_count ) {
         if ( _tic < 51 )
            _stream << "*";
         _stream << std::endl;
      }
   }
};

/*******************************************************/

int main() {
    const int max = 100;
    console_progress_bar progress(max, std::cout);

    for ( int idx = 0; idx < max; ++idx ) {
        ++progress;
        sleep(1);
    }
    
    return 0;
}


Автор: Веталька 4.3.2010, 22:29
Цитата

Второй вариант - выводить в одной и той же знаковой позиции по очереди символы "/", "-", "|", "\" а после них число процентов от принятого файла. Получается эффект вращающейся палочки, символизирующей что процесс идёт и программа не зависла.


заинтересовала тема, подскажите как это реализовать, все таки для консольки нужная вещь

Автор: andrew_121 4.3.2010, 22:47
Цитата(Веталька @  4.3.2010,  22:29 Найти цитируемый пост)
подскажите как это реализовать

что именно? все просто, как пять копеек.

Автор: Ak47black 4.3.2010, 22:53
andrew_121, спасибо что поделились кодом.
Но вот с моим проектом тут трудно применить, понимаете тут я это сразу несказал, мне нужно будет такую-же саму програму написать на java.

Мне вот интересно как можно сделать так, чтобы например строка  отражающая число была в одном месте консоли и при выполнении программы меняла значение?

Автор: bsa 5.3.2010, 01:13
Ak47black, нужно пользоваться специальными кодами. Например, "\b" - возврат курсора на одну позицию назад. std::cout << std::flush - сброс буферов (отображение на консоль без необходимости отправки '\n').

Автор: andrew_121 5.3.2010, 01:25
Цитата(Ak47black @  4.3.2010,  22:53 Найти цитируемый пост)
Мне вот интересно как можно сделать так, чтобы например строка  отражающая число была в одном месте консоли и при выполнении программы меняла значение? 

Код

void myprint(const char* str) {
   fprintf(stdout, "\r%80c\r%s", ' ', str);
}


Добавлено через 1 минуту и 5 секунд
Цитата(Ak47black @  4.3.2010,  22:53 Найти цитируемый пост)
мне нужно будет такую-же саму програму написать на java

и в чем проблема? легко переписывается.

Автор: jhonyxakep 5.3.2010, 08:36
Цитата(bsa @  5.3.2010,  01:13 Найти цитируемый пост)
Ak47black, нужно пользоваться специальными кодами. Например, "\b" - возврат курсора на одну позицию назад. std::cout << std::flush - сброс буферов (отображение на консоль без необходимости отправки '\n').

Или если под винду можно юзать conio.h.

Автор: cutwater 5.3.2010, 09:13
jhonyxakep, можно но не нужно. так как deprecated и obsolete. Нужно пользоваться средствами API тогда уже.

SetConsoleCursorPosition, etc.

Автор: jhonyxakep 5.3.2010, 10:30
Цитата(cutwater @  5.3.2010,  09:13 Найти цитируемый пост)
SetConsoleCursorPosition, etc.

Дык зачем юзать апи, если можно обойтись стандартными средствами, вдополнение зная что они еще и кроссплатформенные: (MinGW - GCC - Watcom - Borland)

Автор: bsa 5.3.2010, 11:05
jhonyxakep, conio.h это совсем вещь не кроссплатформенная и тем более не стандартная.

Автор: jhonyxakep 5.3.2010, 11:40
Цитата(bsa @  5.3.2010,  11:05 Найти цитируемый пост)
jhonyxakep, conio.h это совсем вещь не кроссплатформенная и тем более не стандартная.

 smile Ладн, сорь, но ето я просто предложил как вариант

Автор: Веталька 5.3.2010, 15:46
Цитата

что именно? все просто, как пять копеек.


как выводить символ в одно и то же место?

читая тему увидел /b но вот вопрос а если у меня уже напечатано 10 строк?

Автор: bsa 5.3.2010, 15:58
Веталька, а причем тут прогрессбар? В твоем случае придется использовать нестандартные механизмы.

Автор: Веталька 5.3.2010, 16:11
Цитата

Веталька, а причем тут прогрессбар? В твоем случае придется использовать нестандартные механизмы.


Цитата

Цитата

Второй вариант - выводить в одной и той же знаковой позиции по очереди символы "/", "-", "|", "\" а после них число процентов от принятого файла. Получается
 эффект вращающейся палочки, символизирующей что процесс идёт и программа не зависла.


Цитата

что именно? все просто, как пять копеек.

Автор: andrew_121 5.3.2010, 16:30
Цитата(Веталька @  5.3.2010,  15:46 Найти цитируемый пост)
как выводить символ в одно и то же место?

ты притворяешься? smile очень надеюсь что да.

Автор: bsa 5.3.2010, 16:56
Веталька, а в чем собственно проблема? Не знаешь как создать массив из 4-х символов?
Код
static const char rotSym[] = { '-', '\\', '|', '/' };
Не знаешь как вывести что-то в строку?
Код
int counter = 0;
float percent;
//...
char data[20];
sprintf(data, "%c %.2f%%", rotSym[counter++ % 4], percent);

Не знаешь, как узнать размер строки?
Код
size_t size = strlen(data);

Не знаешь, как вывести строку?
Код
printf("%s", data);

Не знаешь, как вывести символы возврата курсора в нужном количестве?
Код
while(size--)
   fputc('\b', stdout);

Не знаешь как сбросить буфер консоли?
Код
fflush(stdout);

Автор: Веталька 5.3.2010, 17:29
Цитата

ты притворяешься?  очень надеюсь что да.


да, как не печально но я не притворяюсь   smile 

Автор: jhonyxakep 6.3.2010, 04:20
Цитата(Веталька @  5.3.2010,  17:29 Найти цитируемый пост)
да, как не печально но я не притворяюсь    

Да, уж, очень печально....
Код

#include <cstdlib>
#include <iostream>

using namespace std;

int main(int argc, char *argv[])
{
    char *data = "Hello World!";
    char rotSym[4] = { '-', '\\', '|', '/' };
    
    
    
    int size = strlen(data)+1;
    int i=0;
    
    cout <<" " << data;
    
    while(size--) cout <<"\b";
    
    while (1)
    {
    i++;
    cout << rotSym[i]<<"\b";
    
    if (i == 3) i = 0;
    }
    
    system("PAUSE");
    return EXIT_SUCCESS;
}



Вот так бы написал школьник (тк плохо алгоритм расчитан...) smile 

Автор: bsa 6.3.2010, 10:40
jhonyxakep, действительно. Так бы написал школьник, у которого каша в голове из C и C++. Если пишешь на С++, то вместо snprintf следует использовать stringstream. Гораздо удобней, тем более, что заслать нужно количество '\b' можно так:
Код
std::ostringstream stream;
stream << rotSym[counter++ % 4] << ' ' << std::setprecision(2) << percent << '%';
stream << std::setw(stream.str().size()) << std::setfill('\b') << "";
std::cout << stream.str() << std::flush;

Автор: jhonyxakep 7.3.2010, 07:30
Цитата(bsa @  6.3.2010,  10:40 Найти цитируемый пост)
Так бы написал школьник, у которого каша в голове из C и C++. 

 smile это я к тому что задача не особо сложная... даже вовсе не сложная

Автор: xvr 7.3.2010, 16:06
Цитата(Веталька @ 5.3.2010,  15:46)
читая тему увидел /b но вот вопрос а если у меня уже напечатано 10 строк?

Никак. Все progress bar'ы (с использованием ТОЛЬКО стандартного вывода) будут работать в пределах одной строки, т.к. нет стандартного символа для перехода на ПРЕДЫДУЩУЮ строку (только на следующую)

Powered by Invision Power Board (http://www.invisionboard.com)
© Invision Power Services (http://www.invisionpower.com)