首页
学习
活动
专区
圈层
工具
发布
社区首页 >专栏 >Go每日一库之204:gocui(控制台用户界面库)

Go每日一库之204:gocui(控制台用户界面库)

原创
作者头像
luckpunk
修改2025-01-12 11:47:51
修改2025-01-12 11:47:51
6010
举报
文章被收录于专栏:Go每日一库Go每日一库

项目介绍

GOCUI是一个专为Go语言设计的极简主义控制台用户界面(Console User Interface)库。它的设计理念是简单易用,允许开发者创建出富有交互性的控制台应用程序,包括重叠窗口、全局和局部的键绑定以及鼠标支持等功能。

项目技术分析

GOCUI的核心在于其直观的API设计。视图(views),即GUI中的“窗口”,实现了io.ReadWriter接口,这意味着你可以直接对它们进行读写操作。此外,它支持在运行时安全地修改GUI布局,这使得动态更新用户界面变得轻而易举。同时,该库还允许自定义编辑模式,方便构建可复用的组件和复杂的布局。

应用场景

GOCUI可以广泛应用于各种控制台应用中,如:

  1. 命令行工具增强 - 提供更丰富的用户反馈和交互体验。
  2. 数据探索与可视化 - 展示JSON或CSV等数据结构,帮助开发者快速理解和调试。
  3. 实时监控工具 - 显示系统状态信息,如CPU使用率、内存占用等。
  4. 游戏界面 - 创建基于文本的游戏,如冒险游戏或回合制策略游戏。

项目特点

  1. 简洁API - 专注于提供核心功能,降低学习曲线,易于上手。
  2. 视图重叠 - 支持多个视图相互覆盖,增加界面层次感。
  3. 并发安全 - 在运行时修改GUI布局不会引发数据竞争。
  4. 键绑定 - 全局和视图级别的键绑定,实现快捷操作。
  5. 鼠标支持 - 可以通过鼠标进行交互,提升用户体验。
  6. 多彩文本 - 支持彩色显示,使界面更具视觉吸引力。
  7. 定制化 - 定义自己的编辑模式,打造独特的用户体验。

使用

安装

代码语言:javascript
复制
$ go get github.com/jroimartin/gocui

示例

代码语言:javascript
复制
package main

import (
	"fmt"
	"log"

	"github.com/jroimartin/gocui"
)

func main() {
	g, err := gocui.NewGui(gocui.OutputNormal)
	if err != nil {
		log.Panicln(err)
	}
	defer g.Close()

	g.SetManagerFunc(layout)

	if err := g.SetKeybinding("", gocui.KeyCtrlC, gocui.ModNone, quit); err != nil {
		log.Panicln(err)
	}

	if err := g.MainLoop(); err != nil && err != gocui.ErrQuit {
		log.Panicln(err)
	}
}

func layout(g *gocui.Gui) error {
	maxX, maxY := g.Size()
	if v, err := g.SetView("hello", maxX/2-7, maxY/2, maxX/2+7, maxY/2+2); err != nil {
		if err != gocui.ErrUnknownView {
			return err
		}
		fmt.Fprintln(v, "你好,世界!")
	}
	return nil
}

func quit(g *gocui.Gui, v *gocui.View) error {
	return gocui.ErrQuit
}

截图

中文问题

gocui 的中文支持不好,显示中文字符时会漏掉一半文字,因此我给它打了一个补丁,因为该补丁还未被合并到主线中,请从:github.com/rocket049/gocui 或者 https://gitee.com/rocket049/gocui.git 下载源代码,然后复制到目录:GOPATH/src/github.com/jroimartin/gocui。

打了补丁的程序和原程序有2个区别:

  1. 可以正确显示中文;
  2. 多了一个专门用于从编辑窗口读入中文的函数:(v *View) ReadEditor() []byte,该函数用于还原输入的中文语句。

如何使用

我就以一个简单的输入、显示程序做一个例子:

代码语言:javascript
复制
//Try cjk patch. example of view.ReadEditor
package main

import (
    "fmt"
    "log"

    "github.com/jroimartin/gocui"
)
// 输出窗口
func viewOutput(g *gocui.Gui, x0, y0, x1, y1 int) error {
    v, err := g.SetView("out", x0, y0, x1, y1)
    if err != nil {
        if err != gocui.ErrUnknownView {
            return err
        }
        v.Wrap = true
        v.Overwrite = false
        v.Autoscroll = true
        v.SelBgColor = gocui.ColorRed
        v.Title = "Messages"
    }
    return nil
}
// 输入窗口(编辑器)
func viewInput(g *gocui.Gui, x0, y0, x1, y1 int) error {
    if v, err := g.SetView("main", x0, y0, x1, y1); err != nil {
        if err != gocui.ErrUnknownView {
            return err
        }
        v.Editable = true
        v.Wrap = true
        v.Overwrite = false
        if _, err := g.SetCurrentView("main"); err != nil {
            return err
        }
        fmt.Fprintf(v, "example,中文输入示例,按回车输入。press ENTER to input。Ctrl-C 退出")
    }
    return nil
}
// 显示输出、输入窗口
func layout(g *gocui.Gui) error {
    maxX, maxY := g.Size()
    if err := viewOutput(g, 1, 1, maxX-1, maxY-4); err != nil {
        return err
    }
    if err := viewInput(g, 1, maxY-3, maxX-1, maxY-1); err != nil {
        return err
    }
    return nil
}
// 退出函数
func quit(g *gocui.Gui, v *gocui.View) error {
    return gocui.ErrQuit
}
func main() {
    g, err := gocui.NewGui(gocui.OutputNormal)
    if err != nil {
        //log.Panicln(err)
    }

    g.Cursor = true
    g.Mouse = false
    g.ASCII = false

    g.SetManagerFunc(layout)
    if err := g.SetKeybinding("main", gocui.KeyCtrlC, gocui.ModNone, quit); err != nil {
        log.Panicln(err)
    }
    if err := g.SetKeybinding("main", gocui.KeyEnter, gocui.ModNone, updateInput); err != nil {
        log.Panicln(err)
    }
    if err := g.MainLoop(); err != nil && err != gocui.ErrQuit {
        log.Panicln(err)
    }
    g.Close()
}
//updateInput 当按下ENTER键时调用,把输入的内容复制到输出窗口中
func updateInput(g *gocui.Gui, cv *gocui.View) error {
    v, err := g.View("out")
    if cv != nil && err == nil {
        var p = cv.ReadEditor()
        if p != nil {
            v.Write([]byte("你:"))
            v.Write(append(p, '\n'))
        }
        v.Autoscroll = true
    }
    l := len(cv.Buffer())
    cv.MoveCursor(0-l, 0, true)
    cv.Clear()
    return nil
}

效果如何

下面的图片就是我用该程序做的的一个匿名聊天程序界面:

匿名聊天程序

匿名聊天程序的源代码

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

如有侵权,请联系 cloudcommunity@tencent.com 删除。

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

如有侵权,请联系 cloudcommunity@tencent.com 删除。

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 项目介绍
  • 项目技术分析
  • 应用场景
  • 项目特点
  • 使用
    • 安装
    • 示例
    • 截图
  • 中文问题
    • 如何使用
    • 效果如何
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档