Terminal UI

之前用命令行版本的网易云音乐来听歌( musicbox ,在 github 上可以搜索到),觉得实在是太 geek 了,但它是用 python 写的,略微容易崩,所以决定试着用 golang 仿造一个,第一步肯定是模仿它的 UI 了,在浏览器中我们用三元老 HTML/CSS/JS 可以很容易撸出一套能看的前端界面来,但估计没几个人知道命令行版本的 UI 应该怎么搞,其实说实话我也不知道,大概搜了一下,发现用 termui 这个库就可以比较轻松撸出一个与 musicbox 类似的界面了,下面我们来看一下如何用代码来实现吧。

termui 安装

一般来说我们可以使用 go get 来进行获取安装,但最好使用 dep 来帮助我们管理项目的相关依赖。

go get -u github.com/gizak/termui

然后在代码中 import 就可以了。

import "github.com/gizak/termui"

初始化

在使用 termui 时需要先进行初始化( termui.Init() ),并且最后还要释放资源 defer termui.Close()

1
2
3
4
5
err := termui.Init()
if err != nil {
panic(err)
}
defer termui.Close()

界面相关数据准备

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
strs := []string{
" 0. 排行榜",
" 1. 艺术家",
" 2. 新碟上架",
" 3. 精选歌单",
" 4. 我的歌单",
" 5. 主播电台",
" 6. 每日推荐",
" 7. 私人FM",
" 8. 搜索",
" 9. 帮助",
}

off := []string{
" 0. 排行榜",
" 1. 艺术家",
" 2. 新碟上架",
" 3. 精选歌单",
" 4. 我的歌单",
" 5. 主播电台",
" 6. 每日推荐",
" 7. 私人FM",
" 8. 搜索",
" 9. 帮助",
}
on := []string{
"[-> 0. 排行榜](fg-cyan)",
"[-> 1. 艺术家](fg-cyan)",
"[-> 2. 新碟上架](fg-cyan)",
"[-> 3. 精选歌单](fg-cyan)",
"[-> 4. 我的歌单](fg-cyan)",
"[-> 5. 主播电台](fg-cyan)",
"[-> 6. 每日推荐](fg-cyan)",
"[-> 7. 私人FM](fg-cyan)",
"[-> 8. 搜索](fg-cyan)",
"[-> 9. 帮助](fg-cyan)",
}

定义界面参数

在使用 termui 时,我们需要确定界面元素及其属性,以及它在命令行中的排版,其实 UI 就是对数据的一种呈现,反正就是你觉得怎么好看就怎么来。

1
2
3
4
5
6
7
ls := termui.List()
ls.Items = strs
ls.ItemFgColor = termui.ColorWhite
ls.BorderLabel = "网易云音乐"
ls.Height = 12
ls.Width = 20
ls.Y = 0

termui对事件的处理

termui 对事件的处理和 HTTP 处理事件的做法类似,我们需要对不同的事件注册回调函数,例如检测到用户输入 q ,我们注册一个类似的回调函数就可以了。

1
2
3
termui.Handle("/sys/kbd/q", func(termui.Event) {
termui.StopLoop()
})

相关事件可以是键盘输入,界面点击,窗口伸缩甚至可以是自定义事件。相关事件触发后,对应的数据可能会发生改变,这样以来用户界面就需要发生改变,我们可以使用 termui.Render 对界面重新进行渲染。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
cursor := 0
termui.Render(ls)
termui.Handle("/sys/kbd/j", func(termui.Event) {
strs[cursor%len(strs)] = off[cursor%len(strs)]
cursor++
if cursor == len(strs) {
cursor = 0
}
strs[cursor%len(strs)] = on[cursor%len(strs)]
termui.Render(ls)
})
termui.Handle("/sys/kbd/k", func(termui.Event) {
strs[cursor%len(strs)] = off[cursor%len(strs)]
cursor--
if cursor < 0 {
cursor = len(strs) - 1
}
strs[cursor%len(strs)] = on[cursor%len(strs)]
termui.Render(ls)
})
termui.Loop()
Pieces of Valuable Programming Knowledges