Login Register






Tutorial Making multiple independent command line progress bars filter_list
Author
Message
Making multiple independent command line progress bars #1
So, I wrote a tutorial thread today about creating command line program progress bars, for another member on discord. During that conversation we talked about queueing them and making it so you could do simultaneous downloads and display those on screen, then implementing a basic (mutex style) queue. This is a little bit less of a tutorial and more of just a posting, but I went ahead and wrote a demo for it. Here's the code:

Code:
/* simple example of using ncurses to display a queue of progress bars * save this file as ncprogress.c * compile with gcc -o ncp ncprogress.c -pthread -lncurses * change MAX_BARS to the size you want your queue to be * run ./ncp to test it out */ #include <stdlib.h> #include <stdio.h> #include <unistd.h> #include <time.h> #include <pthread.h> #include <ncurses.h> #define MAX_BARS 5 WINDOW *positions[MAX_BARS] = { NULL }; struct progressContext { void (*callback)(unsigned, unsigned, struct progressContext *); WINDOW *win; char *name; }; struct threadContext { struct progressContext *progress; int position; unsigned seconds; pthread_t threadId; }; void waitLoop(unsigned ms, unsigned interval, struct progressContext *context) { unsigned i, j, s, count = ms/interval; for (i = 0, s = 0; i < ms; i += interval, ++s) { (*context->callback)(s % 4, (i * 100) / ms, context); usleep(interval * 1000); } (*context->callback)(0, 100, context); printf("\n"); } void progressw(unsigned spin, unsigned step, struct progressContext *ctx) { int i; const char *pgstep = "|\\-/"; wclear(ctx->win); wprintw(ctx->win, "Your title here, this thread is %s seconds\n[", ctx->name); // print window title first for (i = 0; i < step; ++i) wprintw(ctx->win, "#"); // print bar for (; i < 100; ++i) wprintw(ctx->win, " "); // print blank space wprintw(ctx->win, "] %c ", step > 99 ? ' ' : pgstep[spin]); wrefresh(ctx->win); } void *threadWrapper(void *arg) { } int selectPosition() { int i; for (i = 0; i < MAX_BARS; ++i) if (positions[i] == NULL) return i; return -1; } void *threadEntry(void *arg) { struct threadContext *ctx; struct progressContext *pctx; ctx = arg; pctx = ctx->progress; waitLoop(ctx->seconds * 1000, 1000, pctx); werase(pctx->win); wrefresh(pctx->win); delwin(pctx->win); free(pctx->name); free(pctx); usleep(200 * 1000); positions[ctx->position] = NULL; // put the window back in the list free(ctx); return NULL; } void runThread(unsigned seconds, void (*callback)(unsigned, unsigned, struct progressContext *)) { int position; struct threadContext *ctx; do { position = selectPosition(); } while (position < 0); // wait until we get a window positions[position] = (void *)1; // reserve our spot before we create the window, we will change this later positions[position] = newwin(2, 120, position * 2, 0); // create an ncurses window for it wclear(positions[position]); wrefresh(positions[position]); // initialize the window ctx = malloc(sizeof(struct threadContext)); ctx->threadId = 0; ctx->position = position; ctx->seconds = seconds; ctx->progress = malloc(sizeof(struct progressContext)); ctx->progress->callback = callback; ctx->progress->win = positions[position]; ctx->progress->name = malloc(8); sprintf(ctx->progress->name, "%d", seconds); ctx->threadId = pthread_create(&ctx->threadId, NULL, threadEntry, ctx); } int running() { int i; for (i = 0; i < MAX_BARS; ++i) if (positions[i] != NULL) return 1; return 0; } int main() { int i; const int ndownloads = 18; initscr(); refresh(); noecho(); srand(time(NULL)); for (i = 0; i < ndownloads; ++i) { runThread(rand() % 10 + 5, &progressw); // run for random time between 5 and 10 seconds usleep(750 * 1000); //a time out } sleep(1); // wait for a thread to start while (running()); // loop while we wait refresh(); endwin(); return 0; }

And, for those of you who want the syntax highlighting, click here
Or for the raw code download, click here

Reply