Индикатор выполнения в C для произвольного длинного исполнения - КОНСОЛЬ - PullRequest
0 голосов
/ 31 марта 2020

Я старался изо всех сил искать не только stackOverflow, но и другой веб-сайт, но не смог найти что-то, чтобы соответствовать моим потребностям. Я запрашиваю возможность отображать индикатор выполнения (например, Progress: #### .........). Меня сейчас не волнует%.

Теперь проблема в этом. Я не могу просто сделать 0-100 для l oop, так как код, который я буду sh выполнять и отслеживать, находится в течение времени l oop, который выполняется в течение произвольного времени (размер проблемы зависит от ввода пользователя, таким образом , не является константой).

Я думал о том, чтобы отслеживать количество итераций в переменной int, и пытаюсь сделать по модулю 2, 50 или 100, но, как я уже сказал, количество итераций зависит на входе пользователя и, следовательно, только управляемый при определенных c условиях. Никаких других выходных данных, кроме индикатора выполнения, поэтому я делаю простой printf ('#'); в то время как l oop и все красивые вещи вне его.

Это тоже личное предпочтение, но не против, если его не включить, я бы хотел, чтобы индикатор выполнения был длиной 50 символов, поэтому 100% выполнение = 50 символов '#' соответственно.

Любая помощь приветствуется.

Ответы [ 3 ]

2 голосов
/ 31 марта 2020

Итак, я обернул код до этого, и вот чем я закончил.


Я использовал немного понятия oop и смоделировал класс ProgressBar. Вот как я разработал код для ProgressBar:

struct tagProgressBarData
{
    unsigned long nMaxLen;
    unsigned long nCurLen;

    char FillChr;
    char EmptyChr;
    char LeftMargin;
    char RightMargin;
};
typedef struct tagProgressBarData PBD;

void InitProgressBar(PBD* p, unsigned long MaxLen, char Left, char Right, char Fill, char Empty);
void DrawProgressBar(PBD* p);

Прежде чем переходить к определениям InitProgressBar() и DrawProgressBar(), вот как вы должны использовать то, что я сделал. Вот пример:

int main()
{
    PBD data;

    /** You can chose other characters and change the length too! */
    InitProgressBar(&data, 50, '[', ']', '#', '.');

    /** Now we do something which takes some time. */
    /** Let's just calculate some random cubes. */

    /** The N you talked about. */
    unsigned int N;
    printf("How many numbers to compute: ");
    scanf("%u", &N);

    printf("Calculating the cubes of the first %u numbers.\n", N);
    DrawProgressBar(&data);

    for(unsigned int i = 1; i <= N; i++)
    {
        unsigned int CubeResult = i*i*i;

        unsigned long nProgress = ( ((unsigned long long)i) * data.nMaxLen) / N;
        if (nProgress != data.nCurLen)
        {
            data.nCurLen = nProgress;
            DrawProgressBar(&data);
        }
    }


    return 0;
}

А теперь, определение функции, которая печатает индикатор выполнения:

void DrawProgressBar(PBD* p)
{
    /** Move to the beginning of the line. */
    printf("\r");

    /** Print the left margin char. */
    printf("%c", p->LeftMargin);

    /** Make sure that MaxLen >= CurLen */
    if (p->nMaxLen < p->nCurLen)
        p->nCurLen = p->nMaxLen;

    /** Print the progress with the Fill char. */
    for(unsigned long i = 0; i < p->nCurLen; i++)
        printf("%c", p->FillChr);

    /** Complete whats left with the Fill char. */
    for(unsigned long i = 0; i < p->nMaxLen - p->nCurLen; i++)
        printf("%c", p->EmptyChr);

    /** Print the right margin char. */
    printf("%c", p->RightMargin);
}

Я также использовал эту функцию, чтобы сделать свой код в основном более компактный:

void InitProgressBar(PBD* p, unsigned long MaxLen, char Left, char Right, char Fill, char Empty)
{
    p->nMaxLen = MaxLen;
    p->nCurLen = 0;

    p->LeftMargin = Left;
    p->RightMargin = Right;
    p->FillChr = Fill;
    p->EmptyChr = Empty;
}

Если вы хотите иметь какой-либо текст перед индикатором выполнения, но в той же строке (что-то вроде Progress: [######.............]), вам нужно заменить printf("\r"); из DrawProgressBar() с for l oop, чтобы вы точно вернулись на длину индикатора выполнения.

Также вам понадобится некоторая переменная (скажем, bDrawn), которая сообщит вам, если индикатор выполнения был нарисован хотя бы один раз, так что for для l oop не будет перемещать курсор над существующим текст слева от индикатора выполнения.

0 голосов
/ 01 апреля 2020

Я также сделал это, но, похоже, очень зависит от количества элементов.

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

#include <time.h>

int MAX_PROGRESS = 100;
int BAR_LENGTH = 0;  // Length of Header
int num_items = 30;

void delay(int milliseconds) { 

  // Storing start time 
  clock_t start_time = clock(); 

  // looping till required time is not achieved 
  while (clock() < start_time + milliseconds); 
} 

void initialiseProgressBar(char left, char right, char fill) {

  printf("%c", left);
  for (int i = 0; i < BAR_LENGTH; i ++) {
    printf("%c", fill);
  }

  /** Print the right first (end of line) and then again the left (start of line)
   * as the \r will be placed over it and rewrite from there resulting in one
   * character less
   */
  printf("%c\r%c", right, left);
}

void drawProgressBar(char c) {

  // Print according to BAR_LENGTH
  for (int i = 0; i < 100; i ++) {
    double progress = (i / BAR_LENGTH) % (MAX_PROGRESS * BAR_LENGTH * num_items);
    if (progress == 0) {
      printf("%c", c);
      delay(25);
    }
    // Redraw the stdout stream to show progressing bar
    fflush(stdout);
  }
}

int main(int argc, char* argv[]) {

  // Header
  char* header = "|<------------- Progress Bar ------------->|\n";
  printf("%s", header);
  BAR_LENGTH = strlen(header) - 3; // Account for newline and right character characters

  initialiseProgressBar('[', ']', '.');
  drawProgressBar('#');

  // Footer -- TODO Find better way to finish this without hard coding
  printf("] COMPLETED\n");
  return 0;
}

Предполагая, что вы знаете количество элементов, по которым вы рассчитываете (например, сортировка списка, вычисление разных вещей и т. Д.) c), это должно пригодиться:).

0 голосов
/ 31 марта 2020

После проб и ошибок я мог бы найти решение, но хотел бы проверить кого-либо.

Предполагая, что эти переменные (все типа int):

num_iterations = 0 , MAX_PROGRESS = 100, BAR_LENGTH = 50, num_items = N

Я напечатал символ '#' на:

if ((iteration / BAR_LENGTH) % (MAX_PROGRESS * BAR_LENGTH * num_items) == 0)

и получил желаемый результат:

|<------------- Enumeration Complete ------------->|
|##################################################| COMPLETED

Хотя это постепенно накапливается, оно не имеет формы

|<------------- Enumeration Complete ------------->|
|##################################................|

Все, что я могу сделать с \ r или \ b?

...