【问题标题】:How do you make buttons of the python library "urwid" look pretty?你如何让 python 库“urwid”的按钮看起来很漂亮?
【发布时间】:2019-02-14 14:08:51
【问题描述】:

urwid 中按钮的默认外观非常实用,但在我看来不是很漂亮。 当几个按钮并排排列时,也可能会很烦人。

如何实现按钮显示为带有框架和居中文本并在获得焦点时更改其颜色?

【问题讨论】:

    标签: python button console-application urwid tui


    【解决方案1】:

    您可以使用 Urwid 绘制任何可在终端中使用纯 Unicode 文本绘制的内容,并为每个字符分配前景色和背景色。

    考虑到这一点,不可能绘制出与模型中完全相同的内容,因为要绘制边框,您需要使用the Unicode box drawing characters,这会占用更多空间。

    我开始写一个例子,但遗憾的是现在没有时间完善它。

    我在这里分享它的未完成状态(工作,但选择的外观有问题),希望你会发现它很有用,也许可以作为一个足够好的起点供你摆弄。

    截图:

    代码:

    #!/usr/bin/env python
    # -*- coding: utf-8 -*-
    
    from __future__ import print_function, absolute_import, division
    import urwid
    
    
    PALETTE = [
        ('normal', '', ''),
        ('bold', 'bold', ''),
        ('blue', 'bold', 'dark blue'),
        ('highlight', 'black', 'dark blue'),
    ]
    
    
    def show_or_exit(key):
        if key in ('q', 'Q', 'esc'):
            raise urwid.ExitMainLoop()
    
    
    class CustomButton(urwid.Button):
        button_left = urwid.Text('[')
        button_right = urwid.Text(']')
    
    
    def custom_button(*args, **kwargs):
        b = CustomButton(*args, **kwargs)
        b = urwid.AttrMap(b, '', 'highlight')
        b = urwid.Padding(b, left=4, right=4)
        return b
    
    
    class BoxButton(urwid.WidgetWrap):
        _border_char = u'─'
        def __init__(self, label, on_press=None, user_data=None):
            padding_size = 2
            border = self._border_char * (len(label) + padding_size * 2)
            cursor_position = len(border) + padding_size
    
            self.top = u'┌' + border + u'┐\n'
            self.middle = u'│  ' + label + u'  │\n'
            self.bottom = u'└' + border + u'┘'
    
            # self.widget = urwid.Text([self.top, self.middle, self.bottom])
            self.widget = urwid.Pile([
                urwid.Text(self.top[:-1]),
                urwid.Text(self.middle[:-1]),
                urwid.Text(self.bottom),
            ])
    
            self.widget = urwid.AttrMap(self.widget, '', 'highlight')
    
            # self.widget = urwid.Padding(self.widget, 'center')
            # self.widget = urwid.Filler(self.widget)
    
            # here is a lil hack: use a hidden button for evt handling
            self._hidden_btn = urwid.Button('hidden %s' % label, on_press, user_data)
    
            super(BoxButton, self).__init__(self.widget)
    
        def selectable(self):
            return True
    
        def keypress(self, *args, **kw):
            return self._hidden_btn.keypress(*args, **kw)
    
        def mouse_event(self, *args, **kw):
            return self._hidden_btn.mouse_event(*args, **kw)
    
    
    if __name__ == '__main__':
        header = urwid.Text('Header')
        footer = urwid.Text('Footer')
        onclick = lambda w: footer.set_text('clicked: %r' % w)
        widget = urwid.Pile([
            header,
            urwid.Text('Simple custom buttons:'),
            urwid.Columns([
                custom_button('OK', on_press=onclick),
                custom_button('Cancel', on_press=onclick),
            ]),
            urwid.Text('Box bordered buttons:'),
            urwid.Columns([
                urwid.Padding(BoxButton('OK', on_press=onclick), left=4, right=4),
                BoxButton('Cancel', on_press=onclick),
            ]),
            footer,
        ])
        widget = urwid.Filler(widget, 'top')
        loop = urwid.MainLoop(widget, PALETTE, unhandled_input=show_or_exit)
        loop.run()
    

    【讨论】:

    • 这行得通,但button_leftbutton_right 记录在哪里?
    • 我猜他们没有记录,但你可以在这里的代码中看到它:github.com/urwid/urwid/blob/…
    • 谢谢,我的问题更像是,我们可以依靠他们吗?但我想只有开发人员知道。 :)
    • 我不会担心它,因为:1)它们是公共属性,所以,意味着扩展 2)the code that uses it is trivial,因此如果需要很容易重现
    【解决方案2】:

    在 Elias 的出色回答的基础上,我采用了他的 BoxButton 课程并通过使用 LineBox 而不是手动绘制边框对其进行了一些简化:

    class BoxButton(urwid.WidgetWrap):
        """ Taken from https://stackoverflow.com/a/65871001/778272
        """
        def __init__(self, label, on_click):
            label_widget = urwid.Text(label, align='center')
            self.widget = urwid.LineBox(label_widget)
            self.hidden_button = urwid.Button('hidden button', on_click)
            super(BoxButton, self).__init__(self.widget)
    
        def selectable(self):
            return True
    
        def keypress(self, *args, **kwargs):
            return self.hidden_button.keypress(*args, **kwargs)
    
        def mouse_event(self, *args, **kwargs):
            return self.hidden_button.mouse_event(*args, **kwargs)
    
    

    由容器来设置按钮的宽度。按钮标签将自动居中。使用列连续显示两个按钮的示例:

    urwid.Columns([
        (14, BoxButton('Deploy', on_deploy_clicked)),
        (1, urwid.Text(' ')),  # quick hack to add gap
        (14, BoxButton('Restart', on_restart_clicked)),
    ])
    

    BoxButton 故意不装饰自己。装饰它:

    urwid.AttrMap(BoxButton('Deploy', on_clicked), 'normal', 'highlight')
    

    【讨论】:

      猜你喜欢
      • 2020-06-20
      • 2013-11-17
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2015-11-16
      • 2018-01-08
      • 1970-01-01
      相关资源
      最近更新 更多