Go语言GUI编程包-Ebiten
1. 前言
最近碰到一个题目,就是鼠标选择图片区域,然后把选中的区域进行图像处理,图像处理好说,调用opencv的库函数即可,关键是如何用鼠标选择图片区域,这就涉及到GUI编程了,因此我去了解一下如何使用Go语言的GUI编程。
Go语言没有官方GUI的包,但是有很多第三方的GUI包,比如walk,但是这个包只能在Windows下使用,不能跨平台,我是Linux系统,放弃了选择这个包。
我网上又听说了fyne这个包,我查了一下如何用fyne监听鼠标事件,结果Github上有人提出issue,似乎使用fyne监听鼠标事件挺麻烦的,我就放弃使用fyne了,但是提问者提到了一个叫做Ebiten的库了。
我看了下Ebiten库里面的方法,基本显示图片、监听事件都有,感觉不错,就打算使用它了。
因此我在这里也介绍一些Ebiten库一些简单用法,比如在窗口输出文字、在窗口显示图片、监听鼠标事件。
2. Ebiten库介绍
Ebiten官网:https://ebiten.org/
Ebiten官方API文档:https://pkg.go.dev/github.com/hajimehoshi/ebiten
Ebiten是一个使用Go语言编程库,用于2D游戏开发,可以跨平台。
3. Ebiten在窗口显示文字
不多废话,直接上一个简单的Demo,功能就是弹出一个窗口,输出Hello, World。
package main
import (
"fmt"
"log"
"github.com/hajimehoshi/ebiten"
"github.com/hajimehoshi/ebiten/ebitenutil"
)
/*
空结构体,实现了ebiten.Game接口。
*/
type Game struct{}
/*
Update()是一个成员函数,自动调用
因为这是一个游戏开发的库,界面是需要实时更新的
因此每一个周期,都会更新一次,也就是调用一次Update函数
更新周期是1/60秒,也就是一秒会更新60次
*/
func (g *Game) Update() error {
return nil
}
/*
Draw()用于渲染界面,也是个会自动调用的函数
这个函数的自动调用频率和你电脑显示器的刷新频率一样
screen表示GUI窗口显示的对象,这里是在该窗口输出"Hello, World!"
*/
func (g *Game) Draw(screen *ebiten.Image) {
ebitenutil.DebugPrint(screen, "Hello, World!")
}
/*
Layout()函数的返回值表示显示窗口里面逻辑上屏幕的大小
官网上说参数outsideWidth和outsideHeight是显示在桌面的窗口大小
这里是固定大小640*480
*/
func (g *Game) Layout(outsideWidth, outsideHeight int) (screenWidth, screenHeight int) {
return 640, 480
}
func main() {
// 设置窗口大小是640*480
ebiten.SetWindowSize(640, 480)
// 设置窗口头部,显示Hello, World
ebiten.SetWindowTitle("Hello, World!")
// 运行游戏
if err := ebiten.RunGame(&Game{}); err != nil {
log.Fatal(err)
}
}
显示效果如下图:
GameUpdate()Draw()Layout()main
4. Ebiten在窗口显示图片
Ebiten包提供了一个函数,用于展示一个图片,如下所示:
func (i *Image) DrawImage(img *Image, options *DrawImageOptions) error
参数简单说一下:
img *Image: 被展示的图片
option *DrawImageOption: 展示选项,比如图片的位置,暂不设置
4.1 直接展示图片
比如我要显示下面的图片:
Draw()
func (g *Game) Draw(screen *ebiten.Image) {
// 1. 读取图片文件
f, err := os.Open("gopher.png")
if err != nil {
log.Fatal(err)
}
img, err := png.Decode(f)
if err != nil {
log.Fatal(err)
}
// 把Image文件转成ebiten.Image文件,用于展示
eImg := ebiten.NewImageFromImage(img)
// 在屏幕上展示出图片
screen.DrawImage(eImg, nil)
}
显示效果如下图:
4.1 指定位置展示图片
比如我一个图片要放在屏幕的某个位置,怎样指定坐标呢?
DrawImage()
func (i *Image) DrawImage(img *Image, options *DrawImageOptions) error
但是此时需要指定第二个参数,比如我要把图片显示在窗口的(100,100)坐标处:
func (g *Game) Draw(screen *ebiten.Image) {
// 1. 读取图片文件
f, err := os.Open("gopher.png")
if err != nil {
log.Fatal(err)
}
img, err := png.Decode(f)
if err != nil {
log.Fatal(err)
}
// 把Image文件转成ebiten.Image文件,用于展示
eImg := ebiten.NewImageFromImage(img)
op := &ebiten.DrawImageOptions{}
op.GeoM.Translate(float64(100), float64(100))
// 在屏幕上展示出图片
screen.DrawImage(eImg, op)
}
显示效果:
5. Ebiten监听鼠标事件
监听鼠标事件,这里使用一个简单的例子,刚开始是显示图片的,按下左键,图片消失,松开左键,图片显示。
Draw()
var flag bool
func (g *Game) Draw(screen *ebiten.Image) {
// flag一开始默认是false,会显示图片
if !flag {
screen.DrawImage(eImg, nil)
} else {
screen.Clear()
}
// 监听鼠标事件,如果左键按下,false变成true,图片就会删除
if inpututil.IsMouseButtonJustPressed(ebiten.MouseButtonLeft) {
flag = !flag
}
// 监听鼠标左键松开事件
if inpututil.IsMouseButtonJustReleased(ebiten.MouseButtonLeft) {
flag = !flag
}
}
演示效果如下gif动图所示:
6. 其他
ebiten还有很多功能,我没有提到,主要也就是几个函数的调用,可以自己去查询官方API文档:https://pkg.go.dev/github.com/hajimehoshi/ebiten 。
ebitenutil.DebugPrint(screen, "Hello, World!")
但是如何显示文字呢?比如更改显示文字的颜色、大小等?
但这个需求还真不好实现,这个问题有人在github上也提出了issue: https://github.com/hajimehoshi/ebiten/issues/280 :
作者表示,ebiten库的设计原则是,万物皆Image,因此想要输出特定的文字,需要制作一张带有文字的Image,然后放到窗口中显示出来。。。