Welcome to terminal_layout’s documentation!¶


你可以从 快速开始 开始学习如何使用terminal_layout
Link¶
快速开始¶
欢迎使用terminal_layout,这个项目可以帮你告别单调的命令行输出,使你的输出富有色彩、结构。 你可以通过下面例子快速的了解这个项目
from terminal_layout import *
ctl = LayoutCtl.quick(TableLayout,
[
[TextView('title', 'Student', fore=Fore.black, back=Back.blue, width=17,
gravity=Gravity.center)],
[TextView('', 'No.', width=5, back=Back.blue),
TextView('', 'Name', width=12, back=Back.blue)],
[TextView('st1_no', '1', width=5, back=Back.blue),
TextView('st1_name', 'Bob', width=12, back=Back.blue)],
[TextView('st2_no', '2', width=5, back=Back.blue),
TextView('st2_name', 'Tom', width=12, back=Back.blue)],
]
)
ctl.draw()
ctl.stop()
LayoutCtl
, TableLayout
, TextView
是该项目重要的元素,接下来阅读 输出文字 熟悉如何使用它们。
如需监听键盘事件,则阅读: 监听键盘按键
installation¶
pip install terminal-layout
Python Support¶
Python |
terminal_layout |
---|---|
2.7 |
2.1.x |
3.5+ |
3.x |
输出文字¶
基本概念¶
LayoutCtl :layout管理器,负责绘制所有元素
View : 基础控件,Layout 与 TextView 其实都属于 View
Layout : 布局控制器,控制 TextView 显示的位置。 目前支持的Layout有两种 TableLayout(表格布局), TableRow(行布局)
TextView : 用于显示文字的view。
显示view¶
执行下列代码绘制layout
from terminal_layout import *
table = TableLayout('id1', width=Width.fill)
row1 = TableRow('row1')
row1.add_view(TextView('text1', 'hello',fore=Fore.red))
table.add_view(row1)
table.add_view_list([TableRow('row2'), TableRow('row3')])
ctl = LayoutCtl()
ctl.set_layout(table)
ctl.draw()
ctl.stop()
Note
TableLayout,TableRow,TextView的第一个参数是view的id
使用quick init¶
每次手动创建layout,text_view会很麻烦,这里为 TableRow,TableLayout,LayoutCtl 提供了quick_init()函数帮助快速创建
TableRow¶
from terminal_layout import *
row = TableRow.quick_init('row1', [TextView('title', 'Title', width=Width.wrap)], width=20,
gravity=Gravity.center)
ctl = LayoutCtl(row)
ctl.draw()
ctl.stop()
Note
LayoutCtl()接受的参数是View,因此直接把TableRow放到ctl中。
你也可以把TextView直接放入LayoutCtl(),如:
ctl = LayoutCtl(TextView('title', 'Title', width=10, back=Back.blue))
TableLayout¶
from terminal_layout import *
row1 = TableRow.quick_init('row1', [TextView('title', 'Title', width=Width.wrap)], width=10,
gravity=Gravity.center)
data1_view = TextView('data1', '1.', width=3)
data2_view = TextView('data2', 'foo', width=5)
row2 = TableRow.quick_init('row2', [data1_view, data2_view])
table_layout = TableLayout.quick_init('', [row1, row2], width=10)
ctl = LayoutCtl(table_layout)
ctl.draw()
ctl.stop()
v3.0.0+ data支持 [[TextView]]
这样的形式,且可以通过 row_id_formatter
修改row的默认id。( row_id_formatter
说明见下方 LayoutCtl.quick 部分)
from terminal_layout import *
table = TableLayout.quick_init('root',
[ # table id: root
[TextView('', '1')], # row id: root_row_0
[TextView('', '2')] # row id: root_row_1
] ,
row_id_formatter='{table_id}_row_{index}'
)
LayoutCtl¶
from terminal_layout import *
ctl = LayoutCtl.quick(TableLayout,
# table id: root
[
[TextView('title', 'Title', width=Width.wrap)], # row id: root_row_0
[TextView('data1', '1.', width=3), TextView('data2', 'foo', width=5)], # row id: root_row_1
],
id="root",
row_id_formatter='{table_id}_row_{index}'
)
ctl.draw()
ctl.stop()
Note
v3.0.0开始,可以通过 id
配置最外层的layout id。
创建 TableLayout
时可通过 row_id_formatter
配置 row id。其支持的展位符如下:
table_id :即 id 设置的值
index
修改view的属性¶
使用find_view_by_id获取view并修改(对于重复的id只能获取第一个view)
import time
from terminal_layout import *
ctl = LayoutCtl.quick(TableLayout,
[
[TextView('title', 'Title')], # row id: root_row_0
[TextView('data1', '1.',width=3), TextView('data2', 'foo',width=5)], # row id: root_row_1
]
)
ctl.draw()
row = ctl.find_view_by_id('root_row_0')
row.set_width(10)
row.set_gravity(gravity=Gravity.center)
time.sleep(0.3)
ctl.find_view_by_id('data1').set_text('2.')
time.sleep(0.3)
ctl.find_view_by_id('data2').delay_set_text('FOO')
ctl.stop()
给layout添加view
from terminal_layout import *
from terminal_layout import *
ctl = LayoutCtl.quick(TableLayout, [])
table = ctl.find_view_by_id('root')
# append
table.add_view(TableRow(''))
table.add_view_list([TableRow(''), TableRow('')])
# insert 用法和list相同
table.insert(3, TableRow(''))
Note
因为 TextView
也属于 View
,因此你可以把 TextView
加入 TableLayout
中而不报错。
如:
table = TableLayout('id1')
table.add_view(TextView('', 'text'))
这样某些情况下做相当于
table = TableLayout('id1')
row = TableRow.quick_init('', [TextView('', 'text') ] )
table.add_view(row)
但第一种方式将不能正确处理某些 TextView
的自有属性(非基础 View
的属性)。
除非你知道你在做什么,否则建议使用第二种方式。
移除view¶
你可以使用remove或remove_view_by_id移除view
from terminal_layout import *
ctl = LayoutCtl.quick(TableLayout,
# table id: root
[
[TextView('title', 'Title', width=Width.wrap)], # row id: root_row_0
[TextView('data1', '1.', width=3), TextView('data2', 'foo', width=5)], # row id: root_row_1
]
)
# remove title
ctl.remove_view_by_id('title')
自动刷新¶
v2开始会启动线程自动刷新,因此结束程序时必须手动调用stop()。
如果你不需要,则设置 auto_re_draw为False 禁用,此时你需要手动调用re_draw()
from terminal_layout import *
ctl = LayoutCtl(TextView('title', 'Title', width=10))
ctl.draw(auto_re_draw=False)
time.sleep(0.5)
ctl.find_view_by_id('title').set_fore(Fore.red)
ctl.re_draw()
Note
如果禁用了自动刷新,delay_set_text()函数就无效了
View的属性¶
View的属性包括: width
, visibility
, gravity
TextView在上述基础上增加了:text
, back
, style
, fore
, weight
, weight
,
关于属性的说明参照:属性效果说明
监听键盘按键¶
绑定键盘事件¶
实例化一个 KeyListener
对象,通过 bind_key
绑定key
from terminal_layout import *
key_listener = KeyListener()
@key_listener.bind_key(Key.UP)
def _(kl, e):
print(e)
@key_listener.bind_key(Key.DOWN, 'a', '[0-9]')
def _(kl, e):
if e.key == 'a':
print('Press a')
elif e.key == Key.DOWN:
print('Press DOWN')
elif e.key == '0':
print('Press 0')
else:
print('Press 1-9')
def stop(kl, e):
print('Press', e.key, 'stop!')
kl.stop()
key_listener.bind_key(Key.ENTER,Key.F1, stop, decorator=False)
key_listener.listen(stop_key=[Key.CTRL_A])
bind_key¶
bind_key
绑定的key有三种类型:
Key的成员变量
正则表达式
“any”(任意按键)
其有两种用法,装饰器模式和非装饰器模;
非装饰器模式下,倒数第二个参数为回调的函数,最后一个参数必须是 decorator=False
允许的Key¶
name |
keys |
---|---|
Arrows |
UP, DOWN, LEFT, RIGHT |
Control+ |
CTRL_A, CTRL_B, CTRL_D, CTRL_E, CTRL_F, CTRL_X, CTRL_Z |
F |
F1, F2, F3, F4, F5, F6, F7, F8 |
Other |
ENTER, TAB, BACKSPACE, ESC |
Note
不支持绑定 CTRL_C
如果需要绑定 ESC ,记得修改stop_key。
停止监听¶
有两种方法可以停止监听
回调函数中调用
stop()
开启监听时设置
stop_key
,如果不设置默认为 [Key.ESC]
绑定不在列表中的key¶
bind_key的参数是非常宽松的,因此你可以绑定不在支持列表中的key
from terminal_layout import *
from terminal_layout.readkey.key import KeyInfo
kl = KeyListener()
ctrl_g = KeyInfo('ctrl_g', '\x07')
@kl.bind_key(ctrl_g)
def _(kl, e):
print('按下 ctrl_g', e)
# or
ctrl_h_code = '\x08'
@kl.bind_key(ctrl_h_code)
def _(kl, e):
print('按下 ctrl_h', e)
kl.listen()
属性效果说明¶
属性效果展示
fore & back¶
颜色,背景色
所有值参考 Fore
,Back
类
TextView('','fore',fore=Fore.red)
TextView('','back',back=Back.red)
style¶
样式
所有值参考 Style
类
TextView('','style',style=Style.dim)
width¶
宽度
正整数 :表示所占的字符位数,ascii码占1位,非ascii码占2位
Width.wrap :根据内容决定宽度
Width.fill :填满父布局
TextView('','width',width=10)
weight¶
比重
值是正整数,表示所占比重。
TextView('','weight',weight=1)
weight=2 表示宽度所占比重为2。
比如:
# t1 real_width=2 , t2 real_width=4
TableRow('',[TextView('t1','',weight=1), TextView('t2','',weight=2),] , width=6)
当同时设置weight与width时,使用weight确定宽度
# t1 real_width=3
TableRow('',[TextView('t1','',weight=1, width=10), ] , width=3)
当其他view设置了width时,设置有weight的view按比重分配剩下的宽度
# t2 real_width=2 ,t3 real_width=4
TableRow('',
[
TextView('t1','',width=10),
TextView('t2','',weight=1),
TextView('t3','',weight=2),
] ,
width=16)
gravity¶
对齐方式
Gravity.left : 居左
Gravity.center : 居中
Gravity.right : 居右
TextView('','gravity',gravity=Gravity.left)
visibility¶
是否显示
Visibility.visible :显示
Visibility.invisible :不显示,当占宽度
Visibility.gone :不显示,不占宽度
TextView('','',visibility=Visibility.visible)
ex_style¶
ex_
开头的字体样式,不支持windows
from terminal_layout import *
TextView('','ex_style',style=Style.ex_blink)
ex_fore & ex_back¶
ex_
开头颜色,背景色,不支持windows
from terminal_layout import *
TextView('','ex_fore',fore=Fore.ex_red_1)
TextView('','ex_back',back=Back.ex_red_1)
View¶
View
的概念继承自安卓,一共有两种类型的View,分别是 Layout
与 Widget
。
此项目 Widget
只有 TextView
; Layout
有 TableLayout
, TableRow
-
class
View
¶ View方法说明
-
__init__
(id, width, height=1, visibility=Visibility.visible, gravity=Gravity.left)¶ 初始化
-
id
¶ view的唯一id
-
width
¶ view的宽度,可以是正整数,或者 Width.wrap,Width.fill
-
height
¶ view的高度,暂时没用,始终为1
-
visibility
¶ 是否显示,可选值 :Visibility.visible,Visibility.invisible,Visibility.gone
-
gravity
¶ view内部对其方式,可选值:Gravity.left,Gravity.center,Gravity.right
-
-
get_width
()¶ 获取初始化时设置的width
-
get_real_width
()¶ 最终显示的宽度
-
add_view
(view)¶ 向view中添加一个view
-
insert
(index, view)¶ 向view中每个位置插入一个view
-
remove
()¶ 从父view中移除自身
-
remove_view_by_id
(id)¶ 删除view
-
Layout¶
Layout
是布局控制器,他控制每个 Widget
显示的位置。
TableLayout¶
表格布局
-
class
TableLayout
¶ -
__init__
(id, width=Width.fill, height=1, visibility=Visibility.visible, overflow_vertical=OverflowVertical.none)¶ init,需要注意TableLayout的gravity总是为left
-
classmethod
quick_init
(id, data, width=Width.fill, height=1, visibility=Visibility.visible)¶ 快速初始化,
-
data
¶ 初始的view list
-
-
add_view
(view)¶ 向view中添加一个view
-
add_view_list
(view_list)¶ 向view中添加多个view,
-
TableRow¶
行布局
-
class
TableLayout
¶ -
__init__
(id, width=Width.fill, height=1, back=None, visibility=Visibility.visible, gravity=Gravity.left)¶ init
-
back
¶ 背景色
-
-
classmethod
quick_init
(id, data, width=Width.fill, height=1, back=None, visibility=Visibility.visible, gravity=Gravity.left)¶ 快速初始化
-
data
¶ 初始的view list
-
-
add_view
(view)¶ 向view中添加一个view,只支持添加TextView
-
add_view_list
(view_list)¶ 向view中添加多个view,只支持添加TextView
-
is_show
()¶ view是否显示出来。
在 v2.1.4 之后, 如果 terminal 高度时会隐藏不能显示的部分,此时可通过is_show判断view是否显示。
注意只有使用
scroll
或overflow_vertical
为hidden_top
、hidden_btm
时这个函数返回值才是有意义的, 且只对TableRow
有效,对于TextView
这个返回值一样是无意义的。
-
TextView¶
用于显示文本
扩展¶
progress¶
文档查看:https://github.com/gojuukaze/terminal_layout/tree/master/terminal_layout/extensions/progress

choice¶
文档查看:https://github.com/gojuukaze/terminal_layout/tree/master/terminal_layout/extensions/choice

input¶
文档查看:https://github.com/gojuukaze/terminal_layout/tree/master/terminal_layout/extensions/input

scroll¶
文档查看:https://github.com/gojuukaze/terminal_layout/tree/master/terminal_layout/extensions/scroll

changelog¶
2.1.4¶
TableLayout
添加overflow_vertical
参数,用于terminal高度不够时隐藏row(默认不隐藏)运行环境检测,非Terminal下抛出错误 ( #25 )
添加
remove
,remove_view_by_id
函数choice扩展改用scroll实现滚动
添加
is_show
用于 使用scroll
或overflow_vertical
为hidden_top
、hidden_btm
时判断TableRow
是否隐藏。( 只能判断TableRow )修改一些小bug
2.1.3¶
2.1.2¶
增加input扩展,可以获取文字输入了(不支持windows)
TextView 增加
overflow
属性,用户文本过长时隐藏左边还是右边view 增加 parent 属性
ctl自动重绘可通过设置
refresh_thread_stop
停止重绘
2.0.0¶
auto refresh 增加自动刷新功能
add
delay_set_text()
增加渐进显示字符的函数delay_set_text()
find_view_by_id()
返回ViewProxy
,不再直接返回view增加扩展 extensions
增加按钮监听功能
修复python2 bug
1.0.0¶
FAQ¶
如何获取 View
的宽度¶
View的宽度有两种,width
, real_width
width
: 初始化时设置的宽度值real_width
: 真正绘制的宽度。注意!在绘制之前这个值都不是有效的值
如果需要在绘制之前获取 real_width
,可以调用 LayoutCtl.update_width()
更新宽度后再获取
real_width
不是固定的,终端宽度发生变化这个值就会改变。
因此你可能会需要每次获取 real_width
之前都调用 update_width()
具体参照 https://github.com/gojuukaze/terminal_layout/blob/master/demo/demo6(get_width).py
屏幕闪烁¶
输出的文本太大会出现界面闪烁的情况,这时要调大sys.stdout的缓冲区。具体情况见: https://github.com/gojuukaze/terminal_layout/issues/3
可通过 ctl.set_buffer_size()
函数调大缓冲区。(建议在draw之前调用)