Dynamic terminal printing with python
Sending output to the terminal via the print() command can be done without scrolling if you use the attribute "end".
The default is end='\n' which is a new line.
To suppress scrolling and overwrite the whole previous line, you can use the RETURN escape which is '\r'.
If you only want to rewrite the last four characters, you can use a few back-spaces.
print(value, "_of_", total, end='\r')
NOTE This works for the standard system terminal. The terminal emulator in some tools like IDLE has an error and the '\r' does not work properly, the output is simply concatenated with some non-printable character between.
BONUS INFORMATION FOR print() In the example above, the spaces on each side of "of" are meant to insure white-space between my values and the word "of". However, the default separater of the print() is a " " (space) so we end up with white space between the value and underscore of "_of_".
>> print (value, "_of_", total, end='\r')
8 _of_ 17
The sepparator attribute, sep, can be used to set character between printed items. In my example, I will change it to a null string ('') to make my output suit my needs.
>> print (value, "_of_", total, sep='', end='\r')
8_of_17
As most of the answers have already stated, you really have little option on Linux but to use ncurses
. But what if you aren't on Linux, or want something a little more high-level for creating your terminal UI?
I personally found the lack of a modern, cross-platform terminal API in Python frustrating, so wrote asciimatics to solve this. Not only does it give you a simple cross-platform API, it also provides a lot of higher level abstractions for UI widgets and animations which could be easily used to create a top-like UI.
The simplest way, if you only ever need to update a single line (for instance, creating a progress bar), is to use '\r'
(carriage return) and sys.stdout
:
import sys
import time
for i in range(10):
sys.stdout.write("\r{0}>".format("="*i))
sys.stdout.flush()
time.sleep(0.5)
If you need a proper console UI that support moving the pointer etc., use the curses
module from the standard library:
import time
import curses
def pbar(window):
for i in range(10):
window.addstr(10, 10, "[" + ("=" * i) + ">" + (" " * (10 - i )) + "]")
window.refresh()
time.sleep(0.5)
curses.wrapper(pbar)
It's highly advisable to use the curses.wrapper
function to call your main function, it will take care of cleaning up the terminal in case of an error, so it won't be in an unusable state afterwards.
If you create a more complex UI, you can create multiple windows for different parts of the screen, text input boxes and mouse support.