如何使 python 库 "urwid" 的按钮看起来漂亮?
How do you make buttons of the python library "urwid" look pretty?
urwid 中按钮的默认外观非常实用,但在我看来不是很漂亮。
当几个按钮并排排成一排时,它也会很烦人。
如何实现按钮显示有边框和居中文本,并在获得焦点时改变颜色?
您可以使用 Urwid 绘制任何可在终端中使用纯 Unicode 文本绘制的内容,并为每个字符指定前景色和背景色。
考虑到这一点,不可能绘制出与模型中完全相同的内容,因为绘制边框需要使用the Unicode box drawing characters,这将占用更多space.
我开始写一个例子,但遗憾的是现在没有时间完善它。
我在这里分享未完成的状态(工作,但选择外观有问题),希望您会发现它有用,并且可以作为一个足够好的起点让您 fiddle与.
截图:
代码:
#!/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()
基于 Elias 的出色回答,我采用了他的 BoxButton
class 并通过使用 LineBox
而不是手动绘制边框来简化它:
class BoxButton(urwid.WidgetWrap):
""" Taken from
"""
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')
urwid 中按钮的默认外观非常实用,但在我看来不是很漂亮。 当几个按钮并排排成一排时,它也会很烦人。
如何实现按钮显示有边框和居中文本,并在获得焦点时改变颜色?
您可以使用 Urwid 绘制任何可在终端中使用纯 Unicode 文本绘制的内容,并为每个字符指定前景色和背景色。
考虑到这一点,不可能绘制出与模型中完全相同的内容,因为绘制边框需要使用the Unicode box drawing characters,这将占用更多space.
我开始写一个例子,但遗憾的是现在没有时间完善它。
我在这里分享未完成的状态(工作,但选择外观有问题),希望您会发现它有用,并且可以作为一个足够好的起点让您 fiddle与.
截图:
代码:
#!/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()
基于 Elias 的出色回答,我采用了他的 BoxButton
class 并通过使用 LineBox
而不是手动绘制边框来简化它:
class BoxButton(urwid.WidgetWrap):
""" Taken from
"""
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')