通常来说,Go主要用作后端开发,但也有人用它开发了GUI库,Fyne(Github地址)就是其中一个。
Fyne设计为Material Design风格,支持多个操作系统,如Windows, Mac,也支持编译到移动端(Android, iOS设备)上运行。
下面是使用Fyne完成的纯Go写的简易文件收集器:
- gui.o
package ImageCollector
import (
"fyne.io/fyne/app"
"fyne.io/fyne/widget"
)
type AppGUI struct {
items *widget.Select
srcDir *widget.Entry
outputDir *widget.Entry
btn *widget.Button
}
// 收集对应文件(采用直接移动的方式)
func (ap *AppGUI) Gather() {
ap.srcDir.Disable()
filters := make([]string, 0, 10)
if ap.items.Selected != "" {
filters = append(filters, "."+ap.items.Selected)
}
imgcl := &ImgCollector{}
imgcl.SetDir(ap.srcDir.Text)
imgcl.SetFilters(filters)
imgcl.Run()
}
func (ap *AppGUI) Run() {
ap.srcDir = widget.NewEntry()
ap.outputDir = widget.NewEntry()
ap.items = widget.NewSelect([]string{"bmp", "png", "jpg", "jpeg"}, nil)
ap.btn = widget.NewButton("Run", ap.Gather)
a := app.New()
w := a.NewWindow("图片")
w.SetTitle("图片收集器")
w.SetContent(widget.NewVBox(
ap.srcDir,
ap.outputDir,
ap.items,
ap.btn,
))
w.ShowAndRun()
}
- imgcollector.go
package ImageCollector
import (
"fmt"
"io/ioutil"
"os"
"path"
"path/filepath"
)
var listFilePrefix string = " "
type ImgCollector struct {
dir string
outputDir string
imgTypes []string
}
func (img *ImgCollector) SetDir(dir string) {
img.dir = dir
}
func (img *ImgCollector) SetOutputDir(dir string) {
img.outputDir = dir
}
func (img *ImgCollector) SetFilters(filters []string) {
img.imgTypes = filters
}
func (img *ImgCollector) Run() bool {
if len(img.imgTypes) == 0 {
fmt.Println("no filters")
//return false
} else {
fmt.Println(img.imgTypes[0] + " ==")
}
// print current directory
if img.dir == "" {
//var cwd string
//re, _ := os.Executable()
//cwd = filepath.Dir(re)
//fmt.Println("pwd:" + cwd)
//img.dir = cwd
fmt.Println("no input dir")
return false
}
fmt.Println("img.dir:" + img.dir)
fmt.Println("parent dir:" + filepath.Dir(img.dir))
// if no outpuDir ,create a new temporary one in cwd
if img.outputDir == "" {
pdir := filepath.Dir(img.dir)
tmpdir, err := ioutil.TempDir(pdir, "imgcollector-")
if err != nil {
fmt.Println("error")
}
fmt.Println("temp dir : " + tmpdir)
img.outputDir = tmpdir
}
// list all files
pathSeparator := string(os.PathSeparator)
level := 8
img.listAllFileByName(level, pathSeparator, img.dir)
return true
}
func (img *ImgCollector) listAllFileByName(level int, pathSeparator string, fileDir string) {
files, _ := ioutil.ReadDir(fileDir)
tmpPrefix := ""
for i := 1; i < level; i++ {
tmpPrefix = tmpPrefix + listFilePrefix
}
for _, onefile := range files {
if onefile.IsDir() {
//fmt.Printf("\033[34m %s %s \033[0m \n" , tmpPrefix, onefile.Name());
//fmt.Println(tmpPrefix, onefile.Name(), "目录:")
fmt.Println(onefile.Name())
fmt.Println(filepath.Dir(onefile.Name()))
img.listAllFileByName(level + 1, pathSeparator, fileDir+ pathSeparator+ onefile.Name())
}else {
// judge postfix and move it
postfix := path.Ext(onefile.Name())
for _, v := range img.imgTypes {
if postfix == v {
typePath := img.outputDir + "/" + postfix[1 : len(postfix)]
_, err := os.Stat(typePath)
if err != nil {
if os.IsNotExist(err) {
// make dir
os.Mkdir(typePath, os.ModePerm)
}
}
os.Rename(fileDir + "/" + onefile.Name(), typePath + "/" + onefile.Name())
}
}
}
}
}
整体来说,由于Go的设计风格,使用Fyne时采用的是注入Widget的方式,如果之前做过其它语言GUI的开发,在第一次使用时可能会不太习惯。
界面运行图: