web-dev-qa-db-fra.com

Réécrire plusieurs lignes dans la console

Je sais qu'il est possible de réécrire de manière cohérente la dernière ligne affichée dans le terminal avec "\ r", mais j'ai du mal à déterminer s'il existe un moyen de revenir en arrière et de modifier les lignes précédentes imprimées dans la console.

Ce que je voudrais faire, c'est réimprimer plusieurs lignes pour un RPG basé sur du texte, cependant, un ami se posait également des questions à ce sujet pour une application qui avait une ligne dédiée à une barre de progression et une autre décrivant le téléchargement.

c'est-à-dire que la console imprimerait:

Moving file: NameOfFile.txt  
Total Progress: [########              ] 40%

puis mettez à jour correctement (sur les deux lignes) pendant l'exécution du programme.

35
JRJurman

Sous Unix, utilisez le module curses .

Sous Windows, il existe plusieurs options:

Exemple simple utilisant des malédictions (je suis un total de malédictions n00b):

import curses
import time

def report_progress(filename, progress):
    """progress: 0-10"""
    stdscr.addstr(0, 0, "Moving file: {0}".format(filename))
    stdscr.addstr(1, 0, "Total progress: [{1:10}] {0}%".format(progress * 10, "#" * progress))
    stdscr.refresh()

if __name__ == "__main__":
    stdscr = curses.initscr()
    curses.noecho()
    curses.cbreak()

    try:
        for i in range(10):
            report_progress("file_{0}.txt".format(i), i+1)
            time.sleep(0.5)
    finally:
        curses.echo()
        curses.nocbreak()
        curses.endwin()
44
codeape

En fin de compte, si vous souhaitez manipuler l'écran, vous devez utiliser les bibliothèques de système d'exploitation sous-jacentes, qui seront généralement:

  • curses (ou les codes de contrôle de terminal sous-jacents suivis par la base de données terminfo/termcap) sous Linux ou OSX
  • l'API de la console win32 sous Windows.

La réponse de @codeape vous donne déjà quelques-unes des nombreuses options si cela ne vous dérange pas de coller à un seul système d'exploitation ou si vous êtes heureux d'installer des bibliothèques tierces sur Windows.

Cependant, si vous voulez une solution multiplateforme que vous pouvez simplement installer par pip, vous pouvez utiliser asciimatics . Dans le cadre du développement de ce package, j'ai dû résoudre les différences entre les environnements pour fournir une API unique qui fonctionne sous Linux, OSX et Windows.

Pour les barres de progression, vous pouvez utiliser l'objet BarChart comme indiqué dans cette démo en utilisant ce code .

4
Peter Brittain

Voici un module Python pour les deux Python 2/3, qui peut simplement résoudre une telle situation avec quelques lignes de code; D

réimpression - Un module simple pour Python 2/3 pour imprimer et actualiser le contenu de sortie multi-lignes dans le terminal

Vous pouvez simplement traiter cette instance output comme une normale dict ou list (selon le mode que vous utilisez). Lorsque vous modifiez ce contenu dans l'instance output, la sortie dans le terminal sera automatiquement actualisée: D

Pour votre besoin, voici le code:

from reprint import output
import time

if __name__ == "__main__":
    with output(output_type='dict') as output_lines:
        for i in range(10):
            output_lines['Moving file'] = "File_{}".format(i)
            for progress in range(100):
                output_lines['Total Progress'] = "[{done}{padding}] {percent}%".format(
                    done = "#" * int(progress/10),
                    padding = " " * (10 - int(progress/10)),
                    percent = progress
                    )
                time.sleep(0.05)
3
Yinzo

Comme ça:

#!/usr/bin/env python

import sys
import time
from collections import deque

queue = deque([], 3)
for t in range(20):
    time.sleep(0.5)
    s = "update %d" % t
    for _ in range(len(queue)):
        sys.stdout.write("\x1b[1A\x1b[2K") # move up cursor and delete whole line
    queue.append(s)
    for i in range(len(queue)):
        sys.stdout.write(queue[i] + "\n") # reprint the lines

Je l'ai découvert dans le projet Jiri , écrit en Go.

Encore mieux: effacez toutes les lignes après avoir terminé:

#!/usr/bin/env python

import sys
import time
from collections import deque

queue = deque([], 3)
t = 0
while True:
    time.sleep(0.5)
    if t <= 20:
        s = "update %d" % t
        t += 1
    else:
        s = None
    for _ in range(len(queue)):
        sys.stdout.write("\x1b[1A\x1b[2K") # move up cursor and delete whole line
    if s != None:
        queue.append(s)
    else:
        queue.popleft()
    if len(queue) == 0:
        break
    for i in range(len(queue)):
        sys.stdout.write(queue[i] + "\n") # reprint the lines
0
Leedehai