patterncMajor
Loading... animating dots in C
Viewed 0 times
dotsloadinganimating
Problem
I've recently wanted to make a "Loading..." display in C where the dots print one at a time in order and then reset:
Suprisingly, there isn't much on the internet for doing this well, so I figured I would make a simple program for it.
The output given is seen in the
I know this can be done better. Any suggestions for improvement?
Suprisingly, there isn't much on the internet for doing this well, so I figured I would make a simple program for it.
#include
#include
int main(void)
{
int msec = 0;
const int trigger = 500; // ms
const int printWidth = 4;
int counter = 0;
clock_t before = clock();
while (1)
{
fputs("Loading", stdout);
clock_t difference = clock() - before;
msec = difference * 1000 / CLOCKS_PER_SEC;
if (msec >= trigger)
{
counter++;
msec = 0;
before = clock();
}
for (int i = 0; i < counter; ++i)
{
fputc('.', stdout);
}
for (int i = 0; i < printWidth - counter; ++i)
{
fputc(' ', stdout);
}
fputc('\r', stdout);
fflush(stdout);
if (counter == printWidth)
{
counter = 0;
}
}
}The output given is seen in the
.gif above. I know this can be done better. Any suggestions for improvement?
Solution
Too frenetic
I ran your program but it was very frenetic. It was constantly clearing the "Loading" prompt and reprinting it which resulted in a flickering effect. In addition, the cursor also moved around in a flickery manner (similar to the green box in the animated image).
To improve this, I would do two things:
-
Don't constantly draw when nothing has changed. Instead, sleep until the next trigger time and then redraw. This also has the added benefit of not using 100% of your cpu. Presumably, you will have another thread running which is doing some loading work, and you don't want this thread to hog cpu time.
-
You don't need to clear and redraw the whole prompt until you get to the last dot. Up until that point, you can just draw one dot at a time.
Rewrite
I rewrote your program with the above two fixes in mind:
Rewrite 2
In response to the comment where @syb0rg indicated that the main thread should not sleep, here is what I would do in that case:
I ran your program but it was very frenetic. It was constantly clearing the "Loading" prompt and reprinting it which resulted in a flickering effect. In addition, the cursor also moved around in a flickery manner (similar to the green box in the animated image).
To improve this, I would do two things:
-
Don't constantly draw when nothing has changed. Instead, sleep until the next trigger time and then redraw. This also has the added benefit of not using 100% of your cpu. Presumably, you will have another thread running which is doing some loading work, and you don't want this thread to hog cpu time.
-
You don't need to clear and redraw the whole prompt until you get to the last dot. Up until that point, you can just draw one dot at a time.
Rewrite
I rewrote your program with the above two fixes in mind:
#include
#include
int main(void)
{
const int trigger = 500; // ms
const int numDots = 4;
const char prompt[] = "Loading";
while (1) {
// Return and clear with spaces, then return and print prompt.
printf("\r%*s\r%s", sizeof(prompt) - 1 + numDots, "", prompt);
fflush(stdout);
// Print numDots number of dots, one every trigger milliseconds.
for (int i = 0; i < numDots; i++) {
usleep(trigger * 1000);
fputc('.', stdout);
fflush(stdout);
}
}
}Rewrite 2
In response to the comment where @syb0rg indicated that the main thread should not sleep, here is what I would do in that case:
#include
#include
static void redrawPrompt(void);
static void doWork(void);
int main(void)
{
const int trigger = (CLOCKS_PER_SEC * 500) / 1000; // 500 ms in clocks.
clock_t prevClock = clock() - trigger;
while (1) {
clock_t curClock = clock();
if (curClock - prevClock >= trigger) {
prevClock = curClock;
redrawPrompt();
}
doWork();
}
}
static void redrawPrompt(void)
{
static int numDots;
const int maxDots = 4;
const char prompt[] = "Loading";
// Return and clear with spaces, then return and print prompt.
printf("\r%*s\r%s", sizeof(prompt) - 1 + maxDots, "", prompt);
for (int i = 0; i maxDots)
numDots = 0;
}
static void doWork(void)
{
// This function does loading work but returns at least every 500 ms.
}Code Snippets
#include <stdio.h>
#include <unistd.h>
int main(void)
{
const int trigger = 500; // ms
const int numDots = 4;
const char prompt[] = "Loading";
while (1) {
// Return and clear with spaces, then return and print prompt.
printf("\r%*s\r%s", sizeof(prompt) - 1 + numDots, "", prompt);
fflush(stdout);
// Print numDots number of dots, one every trigger milliseconds.
for (int i = 0; i < numDots; i++) {
usleep(trigger * 1000);
fputc('.', stdout);
fflush(stdout);
}
}
}#include <stdio.h>
#include <time.h>
static void redrawPrompt(void);
static void doWork(void);
int main(void)
{
const int trigger = (CLOCKS_PER_SEC * 500) / 1000; // 500 ms in clocks.
clock_t prevClock = clock() - trigger;
while (1) {
clock_t curClock = clock();
if (curClock - prevClock >= trigger) {
prevClock = curClock;
redrawPrompt();
}
doWork();
}
}
static void redrawPrompt(void)
{
static int numDots;
const int maxDots = 4;
const char prompt[] = "Loading";
// Return and clear with spaces, then return and print prompt.
printf("\r%*s\r%s", sizeof(prompt) - 1 + maxDots, "", prompt);
for (int i = 0; i < numDots; i++)
fputc('.', stdout);
fflush(stdout);
if (++numDots > maxDots)
numDots = 0;
}
static void doWork(void)
{
// This function does loading work but returns at least every 500 ms.
}Context
StackExchange Code Review Q#139440, answer score: 33
Revisions (0)
No revisions yet.