分享一个 Python 命令行下列表选择

讨论 angelfairy
Lv2 初级炼丹师
发布在 Python编程   1488   0
讨论 angelfairy   1488   0

    可以通过上下键 + Enter 来选择,Ctrl+C 取消

    [注意] 只能支持 linux + macos

    超过 20 个数据,会出现 ==== ^ ==== 和 ==== v ==== 提示还有额外数据

    # -*- coding: utf-8 -*-
    import sys
    import termios
    import tty
    
    
    left = u'\u001b[1000D'
    right = u'\u001b[1000C'
    clear_line = u'\u001b[2K'
    up = u'\u001b[1A'
    down = u'\u001b[1B'
    clear_to_bottom = u'\u001b[J'
    
    MAX_SHOW_COUNT = 20
    
    class CommandSingleSelector:
        selectors = None
        cur_index = 0
        cursor_index = -1
        header_word = None
        is_cancel = False
        top_index = 0
        bottom_index = 0
    
        def __init__(self, selectors, header_word):
            self.selectors = selectors
            if len(selectors) > MAX_SHOW_COUNT:
                self.bottom_index = MAX_SHOW_COUNT
            else:
                self.bottom_index = len(selectors) - 1
    
            self.header_word = header_word
    
        def up(self):
            if self.cur_index > 0:
                self.cur_index = self.cur_index - 1
                if self.cur_index < self.top_index:
                    self.top_index = self.top_index - 1
                    self.bottom_index = self.bottom_index - 1
                self.print_multi_line()
    
        def down(self):
            if self.cur_index < len(self.selectors) - 1:
                self.cur_index = self.cur_index + 1
                if self.cur_index > self.bottom_index:
                    self.top_index = self.top_index + 1
                    self.bottom_index = self.bottom_index + 1
                self.print_multi_line()
    
        def exit(self):
            self.clear_multi_line()
    
        def get_selector(self):
            sys.stdout.write(self.header_word + '\n')
            self.print_multi_line()
            is_multi_first = False
            is_multi_second = False
    
            while True:
                fd = sys.stdin.fileno()
                old_settings = termios.tcgetattr(fd)
                try:
                    tty.setraw(sys.stdin.fileno())
                    ch = sys.stdin.read(1)
                    as_code = ord(ch)
    
                    # find the multi key for up/down
                    if as_code == 27:
                        is_multi_first = True
                    elif as_code == 91:
                        if is_multi_first:
                            is_multi_second = True
                    elif as_code == 65:
                        if is_multi_first and is_multi_second:
                            self.up()
                        is_multi_second = False
                        is_multi_first = False
                    elif as_code == 66:
                        if is_multi_first and is_multi_second:
                            self.down()
                        is_multi_second = False
                        is_multi_first = False
                    elif as_code == 13:
                        is_multi_second = False
                        is_multi_first = False
                        self.exit()
                        break
                    elif as_code == 3:
                        is_multi_second = False
                        is_multi_first = False
                        self.exit()
                        self.is_cancel = True
                        break
                    else:
                        is_multi_second = False
                        is_multi_first = False
                finally:
                    termios.tcsetattr(fd, termios.TCSADRAIN, old_settings)
    
            if self.is_cancel:
                raise Exception('Cancel this operation.')
    
            return self.selectors[self.cur_index]
    
        def print_multi_line(self):
            sys.stdout.write((self.cursor_index + 1) * up + left)
            sys.stdout.write(clear_to_bottom)
    
            up_size = self.bottom_index - self.cur_index + 1 + 1 + 1 # first and last word
    
            has_first_sign = '          '
            if self.top_index > 0:
                has_first_sign = '   ==== ^ ===='
    
            sys.stdout.write(left + clear_line + has_first_sign + '\n')
    
    
            for index, item in enumerate(self.selectors):
                if self.top_index <= index <= self.bottom_index:
                    first_word = '   '
                    if index == self.cur_index:
                        first_word = ' > '
                        sys.stdout.write(left + clear_line + first_word + item + '\n')
                    else:
                        sys.stdout.write(left + clear_line + first_word + item + '\n')
            has_last_sign = '          '
            if len(self.selectors) - 1 > self.bottom_index:
                has_last_sign = '   ==== v ===='
            sys.stdout.write(left + clear_line + has_last_sign + '\n')
    
            back_to_cur_index = up * (up_size -1)
            self.cursor_index = self.cur_index - self.top_index
            sys.stdout.write(back_to_cur_index)
            sys.stdout.write(left)
    
        def clear_multi_line(self):
            back_to_top = up * (self.cur_index - self.top_index + 2)
            sys.stdout.write(back_to_top)
            sys.stdout.write(left)
            sys.stdout.write(clear_to_bottom)
    
    
    if __name__ == '__main__':
        selectors = ['HP Printer', 'XiaoMi Printer','DELL Printer']
        command_selector = CommandSingleSelector(selectors=selectors, header_word='Please Select One Printer: ')
        try:
            sel = command_selector.get_selector()
            print sel
        except Exception, e:
            print e.message
    版权声明:作者保留权利,不代表意本站立场。如需转载请联系本站以及作者。

    参与讨论

    回复《 分享一个 Python 命令行下列表选择

    EditorJs 编辑器

    沙发,很寂寞~
    反馈
    to-top--btn