安全小白成长之路

0%

Golang fyne库中文修复方案

前言:

最近一直在学习GO语言,突发奇想想尝试GO的GUI开发,找了关于GUI的适用性和开发难度都比较适宜的库做对比发现还是fyne好一点。以下为关于GO语言GUI库的归档,参考:https://github.com/jobbole/awesome-go-cn/#gui

image.png

fyne安装

首先需要检查GOPATH,若GOPATH不是当前项目的目录则需要修改一下
临时修改方法:

1
export GOPATH="/Users/xxxxx/GoProjects/fynetest"

image-1.png
随后开始安装
使用git上的方法安装v2版本的fyne(需要终端挂上代理),当src目录出现完整的fyne库文件才算下载好。

1
go get fyne.io/fyne/v2

image-2.png

fyne_demo

采用Github上的示例demo代码做简单演示

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
package main

import (
"fyne.io/fyne/v2/app"
"fyne.io/fyne/v2/container"
"fyne.io/fyne/v2/widget"
)

func main() {
a := app.New()
w := a.NewWindow("Hello")

hello := widget.NewLabel("Hello Fyne!")
w.SetContent(container.NewVBox(
hello,
widget.NewButton("Hi!", func() {
hello.SetText("Welcome :)")
}),
))

w.ShowAndRun()
}

go run运行之后即可看到一个简单的窗口。
image-3.png
由于需求原因,想写一个中文的GUI界面,在尝试将几个关键字修改为中文之后发现程序出现乱码。
image-4.png

修复中文问题

方法一:引入系统字体设置成环境变量

首先通过遍历系统字体库来查找合适的字体文件
示例代码如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
package main

import (
"fmt"
"github.com/flopp/go-findfont"
)

func main() {
fontPaths := findfont.List()
for _, path := range fontPaths {
fmt.Println(path)
}
}

注:该方式需要引入github.com/flopp/go-findfont库,需要自行下载该库
运行后可以发现终端输出了很多字体文件的路径
image-5.png
通过对比寻找发现在mac上”/System/Library/Fonts/STHeiti Medium.ttc”字体库适用于中文窗体
windows上同理,可找到”simkai.ttf”字体库
随后修改程序代码,添加”os.Setenv()”设置环境变量,代码如下:

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
package main

import (
"fyne.io/fyne/v2/app"
"fyne.io/fyne/v2/container"
"fyne.io/fyne/v2/widget"
"os"
)

func main() {
os.Setenv("FYNE_FONT", "/System/Library/Fonts/STHeiti Medium.ttc") //设置字体环境
a := app.New()
w := a.NewWindow("Hello")

hello := widget.NewLabel("Fyne测试1")
w.SetContent(container.NewVBox(
hello,
widget.NewButton("点击!", func() {
hello.SetText("Welcome :)")
}),
))

w.ShowAndRun()
os.Unsetenv("FYNE_FONT") //取消环境变量
}

需要注意的是在程序末尾要添加”os.Unsetenv(“FYNE_FONT”)”取消环境变量。
运行代码即可看到程序已正常显示中文
image.png
但是该方法存在一个问题就是当跨平台时可能存在找不到字体文件而导致字体依旧乱码。该方法适合调试时使用,不适合编译后跨平台使用。

方法二:将字体文件编译进程序

首先需要下载阿里巴巴普惠体文件Alibaba-PuHuiTi-Medium.ttf以及fyne官方cmd工具,见文末附件
先将普惠字体文件转换成go文件

1
fyne bundle Alibaba-PuHuiTi-Medium.ttf > bundle.go

image-1.png
检查bundle.go文件发现是将字体文件转换成二进制并定义resourceAlibabaPuHuiTiMediumTtf调用
image-2.png
修改bundle.go中package包名为theme,新建一个theme目录并且在其中新建theme.go文件
image-3.png
theme.go代码如下:

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
package theme

import (
"fyne.io/fyne/v2"
"fyne.io/fyne/v2/theme"
"image/color"
)

type MyTheme struct{

}

var _ fyne.Theme = (*MyTheme)(nil)

func (m MyTheme) Font(s fyne.TextStyle) fyne.Resource {
return ResourceAlibabaPuHuiTiMediumTtf //ResourceSourceHanSansTtf 即是 bundle.go 文件中 var 的变量名
}
func (*MyTheme) Color(n fyne.ThemeColorName, v fyne.ThemeVariant) color.Color {
return theme.DefaultTheme().Color(n, v)
}

func (*MyTheme) Icon(n fyne.ThemeIconName) fyne.Resource {
return theme.DefaultTheme().Icon(n)
}

func (*MyTheme) Size(n fyne.ThemeSizeName) float32 {
return theme.DefaultTheme().Size(n)
}

注:theme.go 中ResourceAlibabaPuHuiTiMediumTtf会报红,但是不影响编译运行
随后在main.go窗体程序运行过程中引入中文字体主题的theme.go代码,在头文件中也需要导入theme包,完整代码如下:

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
package main

import (
"./theme"//导入theme包
"fyne.io/fyne/v2/app"
"fyne.io/fyne/v2/container"
"fyne.io/fyne/v2/widget"
)

func main() {

a := app.New()
a.Settings().SetTheme(&theme.MyTheme{})//引入中文主题
w := a.NewWindow("Hello")

hello := widget.NewLabel("Fyne测试1")
w.SetContent(container.NewVBox(
hello,
widget.NewButton("点击!", func() {
hello.SetText("Welcome :)")
}),
))

w.ShowAndRun()

}

go build编译程序并运行,程序即正常显示中文。
image-4.png
该方法适合编译跨平台程序使用,但是有个不足是因为将字体文件(大小24M)编译进程序的原因,所以编译一个简单的程序都会有24M体积。
以上两种方式各有各的好处,根据需求取舍。

思考:

写完这篇文章的时候突然想到可以根据第一种方法的扩展,那就是先找好win、mac、linux等自己需要跨平台系统上字体文件的具体路径,然后使用runtime.GOOS判断操作系统类型,根据类型调用相应的字体文件来达到不需要将字体文件编译进程序即可正常显示中文字体的目的,并且还减少了因字体文件过大导致程序也相应过大的问题。