在Python中为当前进程设置终端宽度

时间:2017-02-09 16:51:07

标签: python terminal ncurses

我希望使用\r在Python中执行控制台进度条来清除显示。为了支持多行进度条(对于几个并行任务),我想知道是否可以为当前进程设置终端宽度,以便长行包裹?

例如,如果我将终端宽度设置为20,我可以这样做我的进度条:

print '\r%-20s%-20s' % ('Task 1: 30%', 'Task 2: 60%'),
time.sleep(1)
print '\r%-20s%-20s' % ('Task 1: 35%', 'Task 2: 65%'),

我知道可以使用ncurses(或使用ncurses的进度条包),我只是想知道是否有一个解决方案没有使用{ {1}}。

我在https://stackoverflow.com/a/6420070/445810尝试了ncurses,但它没有用,而且行仍然没有包裹。

谢谢!

2 个答案:

答案 0 :(得分:0)

根据您使用的实际终端,使用指示的方法更改终端宽度(rxvt从xterm获得的功能,而该功能又是based on a feature from dtterm)可能/可能不起作用。但还有更直接的方式。

而不是写一个长行和希望终端将它包装起来,你可以

  • 写一个转义序列,将光标移动到左上角,
  • 编写进度条(使用转义序列清除每行的剩余部分),并明确地包装它们,
  • 之前写一个转义序列以清除屏幕的其余部分
  • 在重复这个过程之前等了一会儿

以下是一个例子:

import curses, time, sys

def go_to_top_left():
    curses.putp(curses.tparm(curses.tigetstr("cup"),0,0))

def show_bar(n):
    curses.putp(curses.tigetstr("rev"))
    sys.stdout.write('.' * n)
    sys.stdout.write('*')
    curses.putp(curses.tigetstr("sgr0"))
    curses.putp(curses.tigetstr("el"))
    sys.stdout.write('\n')
    sys.stdout.flush()

def clear_to_bottom():
    curses.putp(curses.tigetstr("ed"))

def progress_bars():
    curses.setupterm()
    foo = 1
    bar = 0
    while foo < 50:
        go_to_top_left()
        show_bar(foo)
        show_bar(bar)
        bar = foo
        foo = foo + 1
        clear_to_bottom()
        time.sleep(1)

progress_bars()

该示例使用curses包中的 terminfo 调用。与 termcap 一样,这些调用不会优化光标的移动,并且您可以控制实际清除屏幕的时间。如果你想完全免除清算,你必须做出几个关于

的假设
  • 进度条的宽度,
  • 屏幕上已有的内容,
  • 您在屏幕上的位置。

(有人可能愿意提供一个硬编码等效于此示例作为&#34;改进&#34;)。

进一步阅读:

答案 1 :(得分:0)

您应该更好地适应终端大小的变化,而不是尝试设置终端宽度。

这个小程序就是这样做的。 运行它并调整终端的大小;观察输出调整大小。

我从this elaborate example获取了IOCTL代码。

import fcntl
import signal
import struct
import sys
import termios
import time

def ioctl_GWINSZ(fd): #### TABULATION FUNCTIONS
    return struct.unpack('hh', fcntl.ioctl(fd, termios.TIOCGWINSZ, '1234'))


def draw_line(width, left_cap, body, right_cap):
    w = sys.stdout.write
    w(left_cap)
    w(body * (width - 2))
    w(right_cap)


def draw_rect(width, height):
    draw_line(width, '/', '-', '\\')
    for n in xrange(height - 3):
        draw_line(width, '|', ' ', '|')
    draw_line(width, '\\', '-', '/')


def draw_screen():
    h, w = ioctl_GWINSZ(1)  # of stdout.
    draw_rect(w, h)
    sys.stdout.write('Rows: %3d, Cols: %3d' % (h, w))
    sys.stdout.flush()


def on_winch(*ignored):
    sys.stdout.write('\n')
    draw_screen()

if __name__ == '__main__':
    draw_screen()
    signal.signal(signal.SIGWINCH, on_winch)
    while True:
        time.sleep(0.1)