ProgrammingThis forum is for all programming questions.
The question does not have to be directly related to Linux and any language is fair game.
Notices
Welcome to LinuxQuestions.org, a friendly and active Linux Community.
You are currently viewing LQ as a guest. By joining our community you will have the ability to post topics, receive our newsletter, use the advanced search, subscribe to threads and access many other special features. Registration is quick, simple and absolutely free. Join our community today!
Note that registered members see fewer ads, and ContentLink is completely disabled once you log in.
If you have any problems with the registration process or your account login, please contact us. If you need to reset your password, click here.
Having a problem logging in? Please visit this page to clear all LQ-related cookies.
Get a virtual cloud desktop with the Linux distro that you want in less than five minutes with Shells! With over 10 pre-installed distros to choose from, the worry-free installation life is here! Whether you are a digital nomad or just looking for flexibility, Shells can put your Linux machine on the device that you want to use.
Exclusive for LQ members, get up to 45% off per month. Click here for more info.
In C++, in a program that runs from the terminal, I want to show some sort of progress meter.
I am thinking of a revolving bar: \ | / -- \ | ,etc. - this would be stationary and the character would change to reflect revolving motion.
Or of a percentage completion number: [10%] -> [36%] -> [100%] - again remain stationary and only the numbers would change.
Or of a progress bar - [****> 23% ] -> [**********> 42% ], etc. this would remain stationary, and the numbers would change and the number of stars in the bar would increase.
How do I do this type of dynamic change on a terminal output?
P.S. This documentation says that in C++ backspace is passed as \b.
You will most likely not want to use backspace, but carriage-return (‘\r’), so you can keep an internal string representation of your bar, print a carriage-return (which moves the cursor to the beginning of the current line, but does not descend to the next line), followed by the entire next line. Here is a previous post pertaining to what you want (except it is not in C++, and there is no revolving bar). Also, take a look at the source of e2fsprogs.
You will most likely not want to use backspace, but carriage-return (‘\r’), so you can keep an internal string representation of your bar, print a carriage-return (which moves the cursor to the beginning of the current line, but does not descend to the next line), followed by the entire next line. Here is a previous post pertaining to what you want (except it is not in C++, and there is no revolving bar). Also, take a look at the source of e2fsprogs.
Thanks for the links! I'll look over the code (and hopefully will understand it).
All you need to know is to use a \r instead of \n (as was suggested) and remember to overwrite the entire used part of the line each time so that you don't have residual display data. You'll really need to use parts of the POSIX C API to make it work reliably because you'll 1) need to write to the terminal or skip the progress bar entirely if there is no terminal, 2) determine the width of the terminal so that you don't get bizarre output for, say, a 20-character terminal. Let us know when you get a basic working version of what you're doing and we'll help with the terminal part if you'd like.
ta0kira
PS Backspace characters don't always perform the function of backspace in the terminal. That only happens if the terminal is set up that way.
Let us know when you get a basic working version of what you're doing and we'll help with the terminal part if you'd like.
Thanks. I think for my current program, the revolving bar will work best (thanks osor for the link). But, I am still going to write a block of code for the progress bar so I'll know how to do it in the future.
I'll post the code in a couple of days after it is written.
It works, but it goes so fast that all you see is the final one. How do I slow it down so that a human can see it spinning?
Actually, it doesn’t. As ta0kira said before, you have to be careful to erase the entire line (overwrite it with spaces) to get a good effect. Now, the second character is always a ‘-’ (which is why it doesn’t appear to change). To correct this behavior, you would need something like:
Code:
else
std::cout << '\r'
<< barspin[whichOne] << ' '
<< " please wait while function is processing";
IMHO, you do not need the second character. It looks out of place, especially if the user is used to a spinner whose width is always 1.
Quote:
Originally Posted by JMJ_coder
I am assuming it has something to do with sleeping or counting a number of clock ticks per cycle, but I have no idea how to do that.
Well, as a demonstration, you could simply do:
Code:
for (i = 0; i < 1000; i++){
rotateBar(i);
sleep(1);
}
In real life, you would need divide your task into chunks and call rotateBar() after each chunk is completed. If you want to use C idioms, it would be best not to pass an argument to the function, and instead give it static storage within the function (so its value is preserved between function calls). If you want to use C++ idioms, you would want to make rotateBar() a member function and the internal state integer a member variable.
IMHO, you do not need the second character. It looks out of place, especially if the user is used to a spinner whose width is always 1.
You know, you're right. I guess I was thinking in the way '-' is half as long as '|', '\', or '/' so print it twice.
Quote:
Originally Posted by osor
Well, as a demonstration, you could simply do:
Code:
for (i = 0; i < 1000; i++){
rotateBar(i);
sleep(1);
}
I tried that before I posted the code here, but I get nothing (so I took it out). The program compiles, but when I run it, it just sits there with no output.
Quote:
Originally Posted by osor
In real life, you would need divide your task into chunks and call rotateBar() after each chunk is completed. If you want to use C idioms, it would be best not to pass an argument to the function, and instead give it static storage within the function (so its value is preserved between function calls). If you want to use C++ idioms, you would want to make rotateBar() a member function and the internal state integer a member variable.
I'll keep that in mind for when I actually will use this. Right now, it is just experimentation on my part.
I tried that before I posted the code here, but I get nothing (so I took it out). The program compiles, but when I run it, it just sits there with no output.
This is because of buffering (I should have tried it out myself). Try putting this statement at the end of rotateBar():
This is because stdout is normally line-buffered (where “line” is defined as a series of characters delimited by the newline character ‘\n’). Since you don’t have this occuring in your writing to stdout, you have to force a buffer flush.
Quote:
Originally Posted by JMJ_coder
Also, sleep() only takes an int for an argument. What if I only want it to sleep for say half a second or a tenth of a second?
This is because stdout is normally line-buffered (where “line” is defined as a series of characters delimited by the newline character ‘\n’). Since you don’t have this occuring in your writing to stdout, you have to force a buffer flush.
LinuxQuestions.org is looking for people interested in writing
Editorials, Articles, Reviews, and more. If you'd like to contribute
content, let us know.