实现类似于top一样的效果用于数据展示

2024-01-19 21:45:15 浏览数 (1)

实现类似于top一样的效果用于数据展示

因为有这样的需求

  1. 想要在terminal里不断刷新一些数据,就类似于输入top命令一样
  2. 但是又不想刷新的这种数据以print的方式输出

大概有这样一些要求。表头固定,然后表头以下的行数据一直不停的刷新。可以实现指定键退出等

发现了一个Python的 curses模块 来实现这个效果

初步代码

代码语言:javascript复制
import curses
import time

def main(stdscr):
    # 禁止光标显示
    curses.curs_set(0)

    # 获取终端窗口的大小
    max_y, max_x = stdscr.getmaxyx()

    # 打印固定的文本
    stdscr.addstr(0, 0, "Fixed text that will not change")

    # 无限循环,不断刷新终端窗口
    while True:
        # 获取当前时间,并将其格式化为字符串
        time_str = time.strftime("%Y-%m-%d %H:%M:%S", time.localtime())

        # 清除终端窗口
        stdscr.clear()

        # 打印固定的文本
        stdscr.addstr(0, 0, "Fixed text that will not change")

        # 打印变化的文本
        stdscr.addstr(1, 0, "Current time is: {}".format(time_str))

        # 刷新终端窗口
        stdscr.refresh()

        # 等待一段时间
        time.sleep(1)

# 运行程序
curses.wrapper(main)

该程序在屏幕上打印出固定的文本Fixed text that will not change,并在下一行打印出当前时间,然后不断刷新屏幕,每秒钟更新一次当前时间。在刷新屏幕时,固定的文本不会变化,而变化的文本会更新。这个效果就和输入top命令后一样了。

addstr()是curses模块中用于向终端窗口添加字符串的函数。它的语法如下:

代码语言:javascript复制
addstr(y, x, str, attrs)

其中,y和x分别表示字符串的行号和列号,从0开始计数,即左上角的坐标为(0, 0)。str表示要添加的字符串,可以是任意长度的字符串。attrs是可选参数,用于设置文本的属性,比如颜色、加粗、下划线等。如果不指定该参数,则默认使用终端窗口的当前属性。

addstr()函数的返回值是一个整数,表示添加的字符串的长度。

在curses模块中还有许多其他的函数,用于控制光标位置、清空终端窗口、设置颜色等。具体用法可以参考curses模块的文档。

制作类似于表格一样的

代码语言:javascript复制
import curses
import time

def main(stdscr):
    # 禁止光标显示
    curses.curs_set(0)

    # 获取终端窗口的大小
    max_y, max_x = stdscr.getmaxyx()

    # 表格的列数
    num_cols = 3

    # 表格中每列的宽度
    col_width = max_x // num_cols

    # 表头
    header = ["Name", "Age", "Score"]

    # 表格数据
    data = [
        ["Alice", "20", "90"],
        ["Bob", "22", "85"],
        ["Charlie", "21", "95"],
    ]

    # 无限循环,不断刷新终端窗口
    while True:
        # 获取当前时间,并将其格式化为字符串
        time_str = time.strftime("%Y-%m-%d %H:%M:%S", time.localtime())

        # 清除终端窗口
        stdscr.clear()

        # 打印固定的文本
        stdscr.addstr(0, 0, "Fixed text that will not change")

        # 打印表头
        for i, col_name in enumerate(header):
            stdscr.addstr(2, i * col_width, col_name.center(col_width))

        # 打印表格数据
        for row_num, row_data in enumerate(data):
            for col_num, cell_data in enumerate(row_data):
                stdscr.addstr(
                    row_num   3,
                    col_num * col_width,
                    cell_data.center(col_width)
                )

        # 打印变化的文本
        stdscr.addstr(8, 0, "Current time is: {}".format(time_str))

        # 刷新终端窗口
        stdscr.refresh()

        # 等待一段时间
        time.sleep(1)

# 运行程序
curses.wrapper(main)

在这个代码中,定义了一个表格,包括表头和表格数据。使用addstr()函数打印出表格,并将其固定在终端窗口的上方。随后,不断更新表格数据,并将其打印在表格下方。其他部分和之前的示例程序相同。

在打印表格时,使用center()函数对字符串进行居中对齐。center()函数的语法如下:

代码语言:javascript复制
center(width, fillchar)

其中,width表示要居中对齐的宽度,fillchar是可选参数,用于指定填充字符。如果不指定该参数,则默认使用空格。

需要注意的是,这个示例程序中的表格只适用于终端窗口的大小,如果终端窗口太小,表格就会超出终端窗口。如果需要适应不同大小的终端窗口,需要动态计算表格的列宽和行高。

也可加入 指定键 用来退出

代码语言:javascript复制
key = self.stdscr.getch()
      if key == ord('q'):  # 如果用户按下 'q' 键
          break  # 退出循环

完整代码

代码语言:javascript复制
import curses
import os, sys

BASE_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
sys.path.append(BASE_DIR)


class StdScr:
    def __init__(self, stdscr):
        self.stdscr = stdscr
        """
        """

    def run(self):
        # 禁止光标显示
        curses.curs_set(0)

        # 获取终端窗口的大小
        max_y, max_x = self.stdscr.getmaxyx()

        # 表头
        header = ["Alice", "20", "90"]

        # 表格的列数
        num_cols = len(header)

        # 表格中每列的宽度
        col_width = max_x // num_cols

        # 表格数据
        data = [
           ["Alice", "20", "90"]
        ]


        # 无限循环,不断刷新终端窗口
        while True:

            # 获取当前时间,并将其格式化为字符串
            time_str = time.strftime("%Y-%m-%d %H:%M:%S", time.localtime())

            # 清除终端窗口
            self.stdscr.clear()

            # 打印固定的文本
            self.stdscr.addstr(0, 0, "Fixed text that will not change")


            # 打印表头
            for i, col_name in enumerate(header):
                self.stdscr.addstr(2, i * col_width, col_name.center(col_width))

            # 打印表格数据
            for row_num, row_data in enumerate(data):
                for col_num, cell_data in enumerate(row_data):
                    self.stdscr.addstr(
                        row_num   3,
                        col_num * col_width,
                        str(cell_data).center(col_width)
                    )

            # 打印变化的文本
            self.stdscr.addstr(8, 0, "Current time is: {}".format(time_str))

            # 刷新终端窗口
            self.stdscr.refresh()

            # 等待一段时间
            time.sleep(3)
            # 可以使用 stdscr.getch() 来获取输入
            key = self.stdscr.getch()
            if key == ord('q'):  # 如果用户按下 'q' 键
                break  # 退出循环
        curses.endwin()


def main(stdscr):
    my_app = StdScr(stdscr)
    my_app.run()


if __name__ == '__main__':
    curses.wrapper(main)

我正在参与2024腾讯技术创作特训营第五期有奖征文,快来和我瓜分大奖!

0 人点赞