4

I have searched the web for a while now, and I still have no idea how to display text in a terminal that's updateable with function. (I'm talking about something like the application install progress bar in Linux updating what it displays)

Is it possible to make a line of text in Terminal that can be updated with a Function in Python?

Thanks in Advance

Eric
  • 678
  • 3
  • 20
  • 2
    From the doc, "The curses library supplies a terminal-independent screen-painting and keyboard-handling facility for text-based terminals". It gives you a full screen and you can "draw" on it using text. Showing progress bar on a command might be a different thing though. – frogcoder Aug 27 '21 at 03:03
  • 1
    For the example, I meant how the text updates, not how it shows a progress bar. Sorry for the Confusion! – Eric Aug 27 '21 at 17:41
  • I found a simpler way, print("\rText", end="") then print("\rText 2", end="") also works – Eric Dec 27 '21 at 18:20

2 Answers2

2

tqdm might be a good choice if you're not looking for something customizable and basic.

For example (given in documentation), you could do:

from tqdm import tqdm
for i in tqdm(range(10000)):
    ...

And it would output a progress bar in the terminal, which would look something like:

76%|████████████████████████████         | 7568/10000 [00:33<00:10, 229.00it/s]
PreciXon
  • 443
  • 2
  • 9
  • For the example, I meant how the text updates, not how it shows a progress bar. Sorry for the Confusion! – Eric Aug 27 '21 at 17:41
1

It's pretty easy to roll your own if you're only working with a single line. Chr(8) (backspace) moves the cursor back a space. Keep track of how many characters you have printed on a line, don't print a newline at the end, and print enough backspaces to get back to where you want to be to print the new text. If the new text is shorter that what's already there, print enough spaces to erase the extra. The only real trick is to make sure you flush output, otherwise it won't show up until you print a newline. (As of Python 3.3 there's a flush parameter on the print() function, which makes that easy.)

Here's a little demo... I was aiming to make Line something resembling an API for this, but don't really have the time to do it properly. Still, maybe you can take it from here...

import time
from io import StringIO

class Line():
    def __init__(self):
        self.value = ""
    def __call__(self, *args, start=0, sep=" "):
        chars = 0
        io = StringIO()
        print(*args, file=io, end="", sep=sep)
        text = io.getvalue()
        self.value = (self.value[:start] + " " * (start - len(self.value))
                      + text + self.value[start + len(text):])
        print(self.value, chr(8) * len(self.value), sep="", end="", flush=True)
    def __next__(self):
        self.value = ""
        print()

def greet():
    line = Line()
    line("hello", start=2)
    time.sleep(1)
    line("world", start=8)
    time.sleep(1)
    line("hi   ", start=2)
    time.sleep(1)
    line("world ", start=7)
    time.sleep(0.3)
    line("world ", start=6)
    time.sleep(0.3)
    line("world ", start=5)
    time.sleep(1)
    line("globe", start=5)
    time.sleep(1)
    for _ in range(4):
        for c in "! ":
            line(c, start=10)
            time.sleep(0.3)
    line("!", start=10)
    time.sleep(1)
    next(line)

greet()
kindall
  • 178,883
  • 35
  • 278
  • 309