Print text before input() prompt in python

后端 未结 3 1033
别跟我提以往
别跟我提以往 2020-12-06 08:31

In Python, is it possible to request user input with input() in the console while simultaneously printing out text in the line BEFORE the prompt? It should look something li

相关标签:
3条回答
  • 2020-12-06 09:16

    Here's another approach using ANSI/VT100 terminal control escape sequences.

    We tell the terminal to only scroll the upper region of the terminal, where the output data is printed, so that the lower region, where the input prompt is printed, stays fixed in place. When we exit the program (using Ctrl C) we need to restore the default scrolling settings.

    This program first clears the screen and then sits in a loop prompting the user for a number n and then prints the numbers in range(n), one per line, with a small time delay to make it easier to see what's happening. The output for each range follows on from the previous range. If the user enters a non-integer the prompt is re-printed. The readline module is imported so that editing and history are available at the input prompt; this module may not be available on all platforms.

    First, a Python 2 version.

    ''' Print text in a scrolling region of the terminal above a fixed line for input
    
        Written by PM 2Ring 2016.05.29
    
        Python 2 version
    '''
    
    from __future__ import print_function
    from time import sleep
    import readline
    
    # Some ANSI/VT100 Terminal Control Escape Sequences
    CSI = '\x1b['
    CLEAR = CSI + '2J'
    CLEAR_LINE = CSI + '2K'
    SAVE_CURSOR = CSI + 's'
    UNSAVE_CURSOR = CSI + 'u'
    
    def emit(*args):
        print(*args, sep='', end='')
    
    def set_scroll(n):
        return CSI + '0;%dr' % n
    
    # Height of scrolling region
    height = 40
    
    GOTO_INPUT = CSI + '%d;0H' % (height + 1)
    
    emit(CLEAR, set_scroll(height))
    
    try:
        while True:
            #Get input
            emit(SAVE_CURSOR, GOTO_INPUT, CLEAR_LINE)
            try:
                n = int(raw_input('Number: '))
            except ValueError:
                continue
            finally:
                emit(UNSAVE_CURSOR)
    
            #Display some output
            for i in range(n):
                print(i)
                sleep(0.1)
    
    except KeyboardInterrupt:
        #Disable scrolling, but leave cursor below the input row
        emit(set_scroll(0), GOTO_INPUT, '\n')
    

    And here's a version that runs on Python 2 and Python 3. When run on Python 3 this script calls shutil.get_terminal_size() to set the height of the scrolling region. It is possible to get the terminal size in Python 2, but the code is rather messy, so I opted for a fixed height.

    I should mention that both versions of this script don't cope well if the terminal size is changed while they are running; handling that properly is left as an exercise for the reader. :)

    ''' Print text in a scrolling region of the terminal above a fixed line for input
    
        Written by PM 2Ring 2016.05.29
    
        Python 2 / 3 version
    '''
    
    from __future__ import print_function
    import sys
    import readline
    from time import sleep
    
    if sys.version_info > (3,):
        # Get the (current) number of lines in the terminal
        import shutil
        height = shutil.get_terminal_size().lines - 1
    
        stdout_write_bytes = sys.stdout.buffer.write
    else:
        height = 40
        input = raw_input
        stdout_write_bytes = sys.stdout.write
    
    
    # Some ANSI/VT100 Terminal Control Escape Sequences
    CSI = b'\x1b['
    CLEAR = CSI + b'2J'
    CLEAR_LINE = CSI + b'2K'
    SAVE_CURSOR = CSI + b's'
    UNSAVE_CURSOR = CSI + b'u'
    
    GOTO_INPUT = CSI + b'%d;0H' % (height + 1)
    
    def emit(*args):
        stdout_write_bytes(b''.join(args))
    
    def set_scroll(n):
        return CSI + b'0;%dr' % n
    
    emit(CLEAR, set_scroll(height))
    
    try:
        while True:
            #Get input
            emit(SAVE_CURSOR, GOTO_INPUT, CLEAR_LINE)
            try:
                n = int(input('Number: '))
            except ValueError:
                continue
            finally:
                emit(UNSAVE_CURSOR)
    
            #Display some output
            for i in range(n):
                print(i)
                sleep(0.1)
    
    except KeyboardInterrupt:
        #Disable scrolling, but leave cursor below the input row
        emit(set_scroll(0), GOTO_INPUT, b'\n')
    
    0 讨论(0)
  • 2020-12-06 09:17

    You could mimic what you want by doing something like this:

    import os
    
    def clear(): os.system('cls')
    
    screen = ""
    prompt = ""
    
    def printToScreen(s):
        global screen, prompt
        clear()
        screen += (s + '\n')
        print(screen)
        print(prompt)
    
    def promptToScreen(p):
        global screen, prompt
        clear()
        print(screen)
        s = input(p)
        prompt = p + s
        return s
    
    #test:
    
    while True:
        s = promptToScreen("Enter anything -- or press 'Enter' to quit: ")
        if len(s) > 0:
            printToScreen(s)
        else:
            break
    

    The following two screen shots shows how it works:

    then:

    This is a Windows solution. In other OS's -- use their command to clear the screen. You could make it more portable by writing clear() so that it issues different commands depending on the OS. The above is mostly proof of concept. The key idea is to maintain a string which represent how you want the terminal to look and then write your own print function which modifies the string, clears the terminal, then prints that screen to the command prompt. Unless you are doing something strange, the amount of overhead is negligible and the clear/update is invisible to the user.

    0 讨论(0)
  • 2020-12-06 09:18

    On Linux you can do it this way:

    #!/usr/bin/python
    
    CURSOR_UP_ONE = '\x1b[1A'
    ERASE_LINE = '\x1b[2K'
    
    print('Text 1\nText 2\nText 3')
    
    inp = ''
    while inp != 'END':
        inp = raw_input('Please enter something:')
        print(CURSOR_UP_ONE + ERASE_LINE + inp)
    

    The point is in moving the cursor one line up every time and erasing the line Please enter something:. Then you can write the input on its place and write the notice about input again, if needed.


    Special strings:

    CURSOR_UP_ONE and ERASE_LINE are strings with special meaning. The complete list if those Terminal escape control sequences you can find HERE.


    Use of ANSI Terminal escape control sequences on Windows:

    To some extent it's possible to use this sequences on Windows too. E.g. those questions deals with this topic:

    • https://superuser.com/questions/413073/windows-console-with-ansi-colors-handling/1050078#1050078
    • How to make win32 console recognize ANSI/VT100 escape sequences?

    Workflow of this script

    0 讨论(0)
提交回复
热议问题