Go进阶:如何开发多彩动感的终端UI应用
女主宣言
之前小编有看过编程语句相关统计,echo、print之类的语句,使用最为频繁。但是直接输出的语句,总是那么的普普通通。所以今天小编来给大家分享一篇关于炫酷输出的文章。希望能对大家有所帮助。
PS:丰富的一线技术、多元化的表现形式,尽在“360云计算”,点关注哦!
1
终端(terminal)的发展历史
终端(Terminal)是计算机系统的输入输出设备,由于历史的原因终端这个概念非常混乱,终端的发展经历了字符终端、图形终端和网络终端三个阶段。
电传打字机的设备TTY(TeleTYpe)
在早期由于计算机非常昂贵,因此数十个用户共用一台主机,为了满足多用户同时使用,最初使用一种叫电传打字机的设备,简称TTY(TeleTYpe),通过专用线缆与中央计算机相连,电传打字机通过键盘将电码信号发送给主机,同时接收主机程序的输出并打印在纸带上,缺点是非常浪费纸,TTY设备是现代控制台(Console)的鼻祖。
VT100
在20世纪70年代后期,VT100由DEC生产。本机具有单色显示屏。我们仍然无法改变颜色,但它能够表达丰富的视觉效果,如闪烁、删除文本,并使文本变为粗体或斜体。为特定操作定义了许多控制序列。
VT100是一个古老的终端定义,后面出现的终端几乎都兼容这种终端。VT100无法表达颜色,因为它嵌入了单色显示器。VT100控制码是用来在终端扩展显示的代码。比如果终端上任意坐标用不同的颜色显示字符。VT100控制码有时又称为ANSI Escape Sequence。如果感兴趣继续了解VT的发展历史请访问vt100.net
VT100控制码ANSI Escape Sequence 顾名思义,所有控制序列开始从\x1b 对应上ASCII码表。今天大多数个人计算机的Telnet用户端提供最普遍的终端(一般VT100)的模拟。VT100无法表达颜色,因为它嵌入了单色显示器。但是不知道为什么VT100控制码ANSI Escape Sequence有改变颜色的控制序列的细节,但VT241终端是高端模型嵌入彩色图形显示器。
让我们了解VT100控制码。所有的控制符是 \033 或 \e 打头(即 ESC 的 ASCII 码)用输出字符语句来输出。可以在命令行用 echo 命令,或者在 C 程序中用 printf 来输出 VT100 的控制字符。
VT100 控制码
\033[0m // 关闭所有属性
\033[1m // 设置为高亮
\033[4m // 下划线
\033[5m // 闪烁
\033[7m // 反显
\033[8m // 消隐
\033[nA // 光标上移 n 行
\033[nB // 光标下移 n 行
\033[nC // 光标右移 n 行
\033[nD // 光标左移 n 行
\033[y;xH // 设置光标位置
\033[2J // 清屏
\033[K // 清除从光标到行尾的内容
\033[s // 保存光标位置
\033[u // 恢复光标位置
\033[?25l // 隐藏光标
\033[?25h // 显示光标
\033[30m – \033[37m为设置前景色
30: 黑色
31: 红色
32: 绿色
33: 黄色
34: 蓝色
35: 紫色
36: 青色
37: 白色
\033[40m – \033[47m 为设置背景色
40: 黑色
41: 红色
42: 绿色
43: 黄色
44: 蓝色
45: 紫色
46: 青色
47: 白色
ANSI / VT100控制码文档
PTY(pseudoTTY)伪终端/网络终端
在一些操作系统中,包括Unix的,一个伪终端,pseudotty,或PTY是一对伪设备,其中,所述一个的从属,模仿硬件文本终端装置,其中,所述其它的主,提供了这样的装置终端仿真器进程控制从站。终端仿真器进程还必须处理终端控制命令,例如,用于调整屏幕的大小。广泛使用的终端仿真程序包括xterm,GNOME终端,Konsole和终端。远程登录处理程序(如ssh和telnet服务器)扮演相同的角色,但与远程用户而不是本地用户进行通信。还要考虑诸如期望之类的程序。
2
Go语言终端colorful-text
打印色彩文字示例
package main
import "fmt"
func main() {fmt.Print("\x1b[4;30;46m")//设置颜色样式fmt.Print("Hello World")//打印文本内容fmt.Println("\x1b[0m")//样式结束符,清楚之前的显示属性
}
运行效果
源代码解析,请关注第4行,这是VT100控制码改变颜色。\x1b[4;30;46m 由3部分组成。
\x1b[ :控制序列导入器
4;30;46:由分号分隔的参数。4表示下划线,30表示设置前景色黑色,46表示设置背景颜色青色
m :最后一个字符(总是一个字符)
打印Hello World后,print\x1b[0m包含0用来表示清除显示属性。
开源库 fatih/color 的原理就是使用golang print VT100控制码(ANSI Escape Sequence)标记文本内容,色彩丰富的终端文本。
3
Go语言终端进度条progress
显示进度条的代码的原理:
终端需要擦除终端
打印进度条
移动光标位置
package mainimport ("fmt""strings""time"
)func renderbar(count, total int) {barwidth := 30done := int(float64(barwidth) * float64(count) / float64(total))fmt.Printf("Progress: \x1b[33m%3d%%\x1b[0m ", count*100/total)fmt.Printf("[%s%s]",strings.Repeat("=", done),strings.Repeat("-", barwidth-done))
}func main() {total := 50for i := 1; i <= total; i++ {//<ESC>表示ASCII“转义”字符,0x1Bfmt.Print("\x1b7") // 保存光标位置 保存光标和Attrs <ESC> 7fmt.Print("\x1b[2k") // 清空当前行的内容 擦除线<ESC> [2Krenderbar(i, total)time.Sleep(50 * time.Millisecond)fmt.Print("\x1b8") // 恢复光标位置 恢复光标和Attrs <ESC> 8}fmt.Println()
}
这部分代码缺陷就是barwidth这个值是固定的,但实际中这个变量应该跟随终端的宽度来确定。
4
关于终端仿真器的窗口大小
我们可以更改窗口大小,因为我们使用pty(终端模拟器),而不是终端机器。在本节中,让我们了解如何获得终端仿真器的大小。要获得窗口大小,你需要 syscall.SYS_IOCTL 使用 TIOCGWINSZ 以下调用。
type winsize struct {Row uint16Col uint16X uint16Y uint16
}func getWinSize(fd int) (row, col uint16, err error) {var ws *winsizeretCode, _, errno := syscall.Syscall(syscall.SYS_IOCTL, uintptr(fd),uintptr(syscall.TIOCGWINSZ),uintptr(unsafe.Pointer(ws)))if int(retCode) == -1 {panic(errno)}return ws.Row, ws.Col, nil
}
但从易用性和简单出发,最好直接调用 unix.IoctlGetWinsize,注意 GetWinsizeAPI 在 windows 上不好使。
package mainimport ("fmt""strings""syscall""time""golang.org/x/sys/unix"
)var wscol = 30func init() {ws, err := unix.IoctlGetWinsize(syscall.Stdout, unix.TIOCGWINSZ)if err != nil {panic(err)}wscol = int(ws.Col)
}func renderbar(count, total int) {barwidth := wscol - len("Progress: 100% []")done := int(float64(barwidth) * float64(count) / float64(total))fmt.Printf("Progress: \x1b[33m%3d%%\x1b[0m ", count*100/total)fmt.Printf("[%s%s]",strings.Repeat("=", done),strings.Repeat("-", barwidth-done))
}func main() {total := 50for i := 1; i <= total; i++ {fmt.Print("\x1b7") // save the cursor positionfmt.Print("\x1b[2k") // erase the current linerenderbar(i, total)time.Sleep(50 * time.Millisecond)fmt.Print("\x1b8") // restore the cursor position}fmt.Println()
}
不仅要了解如何获取窗口大小,还需要知道如何接收事件,通知事件窗口大小更改。
这里以macOS/unix系统为例,你可以从UNIX OS信号接收通知。你只需处理SIGWINCH os信号,如下所示:
package mainimport ("fmt""os""os/signal""strings""syscall""time""golang.org/x/sys/unix"
)var (total = 50count = 0wscol = 20
)func init() {err := updateWSCol()if err != nil {panic(err)}
}func updateWSCol() error {ws, err := unix.IoctlGetWinsize(syscall.Stdout, unix.TIOCGWINSZ)if err != nil {return err}wscol = int(ws.Col)return nil
}func renderbar() {fmt.Print("\x1b7") // 保存光标位置fmt.Print("\x1b[2k") // 清除当前行内容defer fmt.Print("\x1b8") // 恢复光标位置barwidth := wscol - len("Progress: 100% []")done := int(float64(barwidth) * float64(count) / float64(total))fmt.Printf("Progress: \x1b[33m%3d%%\x1b[0m ", count*100/total)fmt.Printf("[%s%s]",strings.Repeat("=", done),strings.Repeat("-", barwidth-done))
}func main() {// set signal handlersigwinch := make(chan os.Signal, 1)defer close(sigwinch)signal.Notify(sigwinch, syscall.SIGWINCH)go func() {for {if _, ok := <-sigwinch; !ok {return}_ = updateWSCol()renderbar()}}()for count = 1; count <= 50; count++ {renderbar()time.Sleep(time.Second)}fmt.Println()
}
通过调用ioctl与TIOCGWINSZ当你收到SIGWINCH signal,你可以得到窗口的大小.您可以从此信息控制终端UI。但是很难正确擦除屏幕。实际上,如果在此代码中使终端窗口变小,则输出将崩溃。最简单的方法是每次都擦除整个屏幕。
总结
思维扩展:根据 ANSI/VT100终端控制码文档结合 python/bash/go/java/c/php 等语言的 print 函数你可以开发出自己的富文本终端UI ap。
参考文档
VT100发展史
ANSI/VT100终端控制码
ANSI/VT100控制码go语言实现:GitHub开源库fatih/color
终端GUI高级示例:https://github.com/jroimartin/gocui
以上就是本篇文章的全部内容了,希望本文的内容对大家的学习或者工作能带来一定的帮助,如果有疑问大家可以留言交流。
360云计算
由360云平台团队打造的技术分享公众号,内容涉及数据库、大数据、微服务、容器、AIOps、IoT等众多技术领域,通过夯实的技术积累和丰富的一线实战经验,为你带来最有料的技术分享
![](/assets/blank.gif)
Go进阶:如何开发多彩动感的终端UI应用相关推荐
- Win10 + VSCode踩坑 + vue项目开发:设置vscode终端为管理员权限
win10系统 如何设置vscode的终端为管理员权限? 一次一次的授权太麻烦! 这里直接更改授权为管理员运行即可. 操作与设置步骤: "桌面找到"VSCode"程序图标 ...
- 项目管理进阶--软件开发项目中的团队组成
#项目管理进阶–软件开发项目中的团队组成 ##项目经理 项目经理负责分配资源,确定优先级,协调与客户和用户之间的交往.总而言之,就是尽量使项目团队一直集中于正确的目标.项目经理还要建立一套工作方法,以 ...
- HBase入门至进阶以及开发等知识梳理
HBase入门至进阶以及开发等知识梳理 HBase简介 hadoop简介 Hadoop是一个由Apache基金会所开发的分布式系统基础架构.用户可以在不了解分布式底层细节的情况下,开发分布式程序.充分 ...
- [Android] Android开发优化之——对界面UI的优化(2)
在Android应用开发过程中,屏幕上控件的布局代码和程序的逻辑代码通常是分开的.界面的布局代码是放在一个独立的xml文件中的,这个文件里面是树型组织的,控制着页面的布局.通常,在这个页面中会用到很多 ...
- Win10 UWP开发中的重复性静态UI绘制小技巧 1
Win10 UWP开发中的重复性静态UI绘制小技巧 1 原文:Win10 UWP开发中的重复性静态UI绘制小技巧 1 介绍 在Windows 10 UWP界面实现的过程中,有时会遇到一些重复性的.静态 ...
- lua运行外部程序_LTUI v2.2 发布, 一个基于lua的跨平台字符终端UI界面库
LTUI是一个基于lua的跨平台字符终端UI界面库. 此框架源于xmake中图形化菜单配置的需求,类似linux kernel的menuconf去配置编译参数,因此基于curses和lua实现了一整套 ...
- 超炫酷的 Docker 终端 UI lazydocker,想看哪里点哪里
有开发者开源了一个用于 Docker 和 docker-compose 的简单终端 UI -- lazydocker,才短短几天目前已经收获了 2k+ star. 作者表示记住 Docker 命令很难 ...
- 我的日记本开发手记(4)—— UI效果图
前面我已经对配色和布局进行了出版规划,现在是真正动手的时候了,开始漂亮的皮囊设计之旅吧!工欲善其事,必先利其器,我选择的工具是大名鼎鼎的Adobe公司开发的Photoshop软件,版本为Adobe P ...
- Kubernetes:基于命令行终端UI的管理工具 K9s
写在前面 K9s 是一个基于终端UI的 K8S 管理工具 博文内容为 k9s 在 windows.Linux 以及docker 安装Demo 简单的 热键使用. 理解不足小伙伴帮忙指正 我所渴求的,無 ...
最新文章
- SAP HR模块的基础数据表和增强配置
- linux 文件系统覆盖目录,Linux内核裁减及根文件系统定制
- 2006年清华大学计算机研究生机试真题
- Java常见排序算法之直接选择排序
- [html] 隐藏div内文字的方法有哪些?
- array.prototype.map()如何工作
- HttpwebRequest - 带ViewState的网页POST请求
- sql2005 脚本中给字段写说明
- python glob模块
- mysql如何进行宿舍分配_手把手教你做一个Jsp Servlet Mysql实现的学生宿舍管理系统...
- LoadRunner11在Win10 下的破解解决办法(整合)
- 常用汇编指令 rep movs / rep stos
- Android内存和SD卡的数据存取
- html不能打开图片,HTML无法打开图片
- MySQL数据的备份与恢复
- python画球鞋_基于Python爬虫原理的篮球鞋选择程序的设计与实现
- 【小强推歌】---Shania Twain 经典歌曲收藏
- 回复英文审稿人意见常用格式
- 卸载conda安装的环境
- 项目_MySQL比较字符大小的小坑
热门文章
- Hyperledger fabric学习笔记(一)
- django自定义模板标签,通过键获取字典的值,屏蔽姓名等隐蔽信息并调用展示到页面上
- springMVC小记
- c++语言中for循环语句,C++ 循环
- unity和python通讯_Python 与 Unity mlagents 交互 API
- python中outside loop_Python入门指引
- mysql bin值总是变化_MySQL|update字段为相同的值是否会记录binlog
- flask简单登录注册
- 查看数据库大小或者表大小
- Python 操作redis 常用方法