资讯详情

Golang Fyne项目实战(含源码)

Golang Fyne项目实战(含源码)

  • 项目介绍
    • 效果图
    • 功能介绍
    • 步骤介绍
  • 代码区域
    • 项目结构
    • 下载fyne包以及Fyne工具包
    • 追加静态资源,程序设置图标
    • 完整代码
  • 结尾

项目介绍

效果图

在这里插入图片描述

功能介绍

根据文本文件的内容,自动更名所选文件夹中的文件名称

步骤介绍

1.创建txt在内容程序界面中输入文本文件"目录文件"选择当前创建的文本文件 例:

2.选择需要批量更改名称的文件夹 3.选择路径后,程序单击"开始更名",自动更名 4.结果

代码区域

项目结构

下载fyne包以及Fyne工具包

命令: 1.go get fyne.io/fyne/v2 2.go get fyne.io/fyne/cmd/fyne

追加静态资源,程序设置图标

1.将静态资源编译成 go 文件 (打开终端执行自己的项目录):fyne bundle fav.png >> bundled.go 2. 打开 bundled.go 文件会看到变量 resourceFavPng 3.设置窗口图标,任务栏图标 ///主代码 a := app.New() a.SetIcon(resourceFavPng) //本地操作注释,否则报错,打包时打开此行代码

完整代码

package main  import (  "YHSoft/Demo/GUIDemo/FyneDemo/02_RenameFileName/models" ////用自己的项目路径代替  "errors"  "fmt"  "fyne.io/fyne/v2"  "fyne.io/fyne/v2/app"  "fyne.io/fyne/v2/container"  "fyne.io/fyne/v2/dialog"  "fyne.io/fyne/v2/layout"  "fyne.io/fyne/v2/storage"  "fyne.io/fyne/v2/widget"  "github.com/flopp/go-findfont"  "io/ioutil"  "log"  "os"  "path/filepath"  "strconv"  "strings"  "time"  "unicode" )  func main() { 
          ///新建一个app  a := app.New()  //设置窗栏,任务栏图标  a.SetIcon(resourceIconPng)  ///新窗口  w := a.NewWindow("自动更名程序V1.0")  ///主界面框架布局  MainShow(w)  //尺寸  w.Resize(fyne.Size{ 
        Width: 500, Height: 100})  //w居中显示  w.CenterOnScreen()  //循环运行  w.ShowAnRun()

	err := os.Unsetenv("FYNE_FONT")
	if err != nil { 
        
		return
	}
}

var tileInfo string
var done = make(chan bool)
var stop = make(chan int, 1)
var num int64

// MainShow 主界面函数
func MainShow(w fyne.Window) { 
        
	//var ctrl *beep.Ctrl
	title := widget.NewLabel("自动化更名程序")
	hello := widget.NewLabel("目录文件:")
	entry1 := widget.NewEntry() //文本输入框
	//entry1.SetText("E:\\rename_temp2\\123.txt")

	dia1 := widget.NewButton("打开", func() { 
         //回调函数:打开选择文件对话框
		fd := dialog.NewFileOpen(func(reader fyne.URIReadCloser, err error) { 
        
			if err != nil { 
        
				dialog.ShowError(err, w)
				return
			}
			if reader == nil { 
        
				log.Println("Cancelled")
				return
			}

			entry1.SetText(reader.URI().Path()) //把读取到的路径显示到输入框中
		}, w)

		fd.SetFilter(storage.NewExtensionFileFilter([]string{ 
        ".txt"})) //打开的文件格式类型
		fd.Show()                                                      //控制是否弹出选择文件目录对话框
	})

	text := widget.NewMultiLineEntry() //多行输入组件
	//text.Disable() //禁用输入框,不能更改数据

	labelLast := widget.NewLabel("发飙的蜗牛 ALL Right Reserved")
	//labelLast := widget.NewLabel(" ")
	label4 := widget.NewLabel("文件路径:")
	entry2 := widget.NewEntry()

	//entry2.SetText("E:\\rename_temp2\\宝岗路停车场项目幕墙施工图PDF")

	dia2 := widget.NewButton("打开", func() { 
        
		dialog.ShowFolderOpen(func(list fyne.ListableURI, err error) { 
        
			if err != nil { 
        
				dialog.ShowError(err, w)
				return
			}
			if list == nil { 
        
				log.Println("Cancelled")
				return
			}
			//设置输入框内容
			entry2.SetText(list.Path())
		}, w)
	})

	//开始更名按钮
	bt3 := widget.NewButton("开始 更名", func() { 
        
		go func() { 
        
			if (entry1.Text != "") && (entry2.Text != "") { 
        
				text.SetText("")
				text.Refresh()
				if num != 0 { 
        
					stop <- 1
					return
				} else { 
        
					err := generateTxt(entry1.Text, entry2.Text, text)
					if err != nil { 
        
						dialog.ShowError(err, w)
					}
					text.Refresh()
				}
			} else { 
        
				dialog.ShowError(errors.New("读取TXT文件错误"), w)
			}
		}()

	})

	//停止更名按钮
	bt4 := widget.NewButton("停止 更名", func() { 
        
		go func() { 
        
			done <- false
		}()
	})

	head := container.NewCenter(title)

	v1 := container.NewBorder(layout.NewSpacer(), layout.NewSpacer(), hello, dia1, entry1)
	v4 := container.NewBorder(layout.NewSpacer(), layout.NewSpacer(), label4, dia2, entry2)

	v5 := container.NewHBox(bt3, bt4)
	v5Center := container.NewCenter(v5)

	ctnt := container.NewVBox(head, v1, v4, v5Center, text, labelLast) //控制显示位置顺序
	w.SetContent(ctnt)
}

//设置字体
func init() { 
        
	fontPaths := findfont.List()
	for _, fontPath := range fontPaths { 
        
		//fmt.Println(fontPath)
		//楷体:simkai.ttf
		//黑体:simhei.ttf
		//微软雅黑:msyh.ttc
		if strings.Contains(fontPath, "simkai.ttf") { 
        
			err := os.Setenv("FYNE_FONT", fontPath)
			if err != nil { 
        
				return
			}
			break
		}
	}
}

//读取数据校验数据
func generateTxt(inPath, outPath string, text *widget.Entry) error { 
        
	//标题
	tileInfo += "开始处理,正在读取文件...\n"
	text.SetText(tileInfo)

	nameList,err := models.GetStrList(inPath)
	if err != nil{ 
        
		tileInfo += "读取文件出错...\n"
		text.SetText(tileInfo)
	}


	//获取文件路径的文件
	files, _ := ioutil.ReadDir(outPath)

	var fileNameList []string

	for _, file := range files { 
        
		// 带扩展名的文件名
		fullFilename := file.Name()

		//添加文件数据到切片中
		fileNameList = append(fileNameList, fullFilename)
	}

	if len(nameList) == 0 || len(fileNameList) == 0{ 
        
		tileInfo += "已停止处理...\n"
		text.SetText(tileInfo) //设置多行显示控件中的内容
		return errors.New("找不到路径或路径下不存在此文件")
	}

	if len(nameList) != len(fileNameList) { 
        
		tileInfo += "已停止处理...\n"
		text.SetText(tileInfo) //设置多行显示控件中的内容
		return errors.New("目录行数与文件行数不相等,请检查!")
	}

	renameFile(nameList, fileNameList, outPath, text)

	return nil
}

//操作更名文件
func renameFile(nameList []string, fileNameList []string, outPath string, text *widget.Entry) { 
        
	var newName string

	//遍历更改
	for index, fullFilename := range fileNameList { 
        
		select { 
        
		case <-done: //读管道中内容,没有内容前,阻塞
			//扩展名
			fileExt := filepath.Ext(fullFilename)

			//fmt.Println("nameList[index]=",nameList[index])
			defaultName := nameList[index] //文本文件初始名称
			var defaultNameCode []string
			var defaultNameNewCode string

			rune := []rune(defaultName)
			for i := len(rune); i > 0; i-- { 
        
				if !unicode.Is(unicode.Han, rune[i-1]) { 
        
					defaultNameCode = append(defaultNameCode, string(rune[i-1]))
				} else { 
        
					break
				}
			}

			//重新编排名称编号
			for i := len(defaultNameCode); i > 0; i-- { 
        
				defaultNameNewCode += defaultNameCode[i-1]
			}

			//fmt.Println("defaultName=", defaultName)

			//重组新名称
			newName = strconv.Itoa(index+1) + " " + strings.ReplaceAll(defaultName, defaultNameNewCode, "") + " " + defaultNameNewCode

			// 不带扩展名的文件名
			//filenameOnly := strings.TrimSuffix(fullFilename, fileExt)

			//将每个文件名后面加上1,扩展名不变
			err := os.Rename(outPath+`\`+fullFilename, outPath+`\`+newName+fileExt)
			if err != nil { 
        
				fmt.Println("err=", err)
			}

			tileInfo += "处理数据文件:" + fullFilename + "\n"
			time.Sleep(time.Second * 1)
			text.SetText(tileInfo) //设置多行显示控件中的 内容

			tileInfo += "停止更名...\n"
			text.SetText(tileInfo) //设置多行显示控件中的内容
			num = num + 1
			<-stop //读管道中内容,没有内容前,阻塞
		default:
			//扩展名
			fileExt := filepath.Ext(fullFilename)

			//fmt.Println("nameList[index]=",nameList[index])
			defaultName := nameList[index] //文本文件初始名称
			var defaultNameCode []string
			var defaultNameNewCode string

			rune := []rune(defaultName)
			for i := len(rune); i > 0; i-- { 
        
				if !unicode.Is(unicode.Han, rune[i-1]) { 
        
					defaultNameCode = append(defaultNameCode, string(rune[i-1]))
				} else { 
        
					break
				}
			}

			//重新编排名称编号
			for i := len(defaultNameCode); i > 0; i-- { 
        
				defaultNameNewCode += defaultNameCode[i-1]
			}

			//fmt.Println("defaultName=", defaultName)

			//重组新名称
			newName = strconv.Itoa(index+1) + " " + strings.ReplaceAll(defaultName, defaultNameNewCode, "") + " " + defaultNameNewCode

			// 不带扩展名的文件名
			//filenameOnly := strings.TrimSuffix(fullFilename, fileExt)

			//将每个文件名后面加上1,扩展名不变
			err := os.Rename(outPath+`\`+fullFilename, outPath+`\`+newName+fileExt)
			if err != nil { 
        
				fmt.Println("err=", err)
			}

			tileInfo += "处理数据文件:" + fullFilename + "\n"
			//time.Sleep(time.Second * 1)
			text.SetText(tileInfo) //设置多行显示控件中的 内容
		}
	}
	tileInfo += "处理完毕!"
	text.SetText(tileInfo) //设置多行显示控件中的内容
	num = 0
}

package models

import (
	"bufio"
	"fmt"
	"github.com/axgle/mahonia"
	"io"
	"os"
	"strings"
)


//读取txt文件,自动判断编码格式
func GetStrList(path string)([]string,error){ 
        
	f, err := os.Open(path) //打开目录路径txt文件
	if err != nil { 
        
		return nil, err
	}
	defer f.Close() //最后关闭文件

	r := bufio.NewReader(f)

	buf := make([]byte, 1024)
	var res string

	_, err = r.Read(buf)
	if err != nil && err != io.EOF { 
        
		return nil,err
	}

	res = GetStrCoding(buf)

	if res == "UTF8" { 
        
		return GetTextContentUTF8(path),nil
	} else { 
        
		return GetTextContentGbk(path),nil
	}
}

//读取gbk编码格式的文件
func GetTextContentGbk(txtPath string) []string { 
        
	f, err := os.Open(txtPath) //打开目录路径txt文件
	if err != nil { 
        
		fmt.Println("err=", err)
	}
	defer f.Close()

	decoder := mahonia.NewDecoder("gbk")
	r := bufio.NewReader(decoder.NewReader(f))

	chunks := []byte{ 
        }
	buf := make([]byte, 1024)

	for { 
        
		n, err := r.Read(buf)
		if err != nil && err != io.EOF { 
        
			panic(err)
		}
		if 0 == n { 
        
			break
		}
		chunks = append(chunks, buf[:n]...)
	}

	nameStr := strings.ReplaceAll(string(chunks), "\r\n", ",")
	return strings.Split(nameStr, ",")
}

//读取utf8编码格式的文件
func GetTextContentUTF8(txtPath string) []string { 
        
	f, err := os.Open(txtPath) //打开目录路径txt文件
	if err != nil { 
        
		fmt.Println("err=", err)
	}
	defer f.Close()

	r := bufio.NewReader(f)
	chunks := []byte{ 
        }
	buf := make([]byte, 1024)
	for { 
        
		n, err := r.Read(buf)
		if err != nil && err != io.EOF { 
        
			panic(err)
		}
		if 0 == n { 
        
			break
		}
		chunks = append(chunks, buf[:n]...)
	}

	nameStr := strings.ReplaceAll(string(chunks), "\r\n", ",")
	return strings.Split(nameStr, ",")
}

const (
	GBK     string = "GBK"
	UTF8    string = "UTF8"
	UNKNOWN string = "UNKNOWN"
)

//判断文本文件格式
func GetStrCoding(data []byte) string { 
        
	if isUtf8(data) == true { 
        
		return UTF8
	} else if isGBK(data) == true { 
        
		return GBK
	} else { 
        
		return UNKNOWN
	}
}


func isGBK(data []byte) bool { 
        
	length := len(data)
	var i = 0
	for i < length { 
        
		if data[i] <= 0x7f { 
        
			//编码0~127,只有一个字节的编码,兼容ASCII码
			i++
			continue
		} else { 
        
			//大于127的使用双字节编码,落在gbk编码范围内的字符
			if data[i] >= 0x81 &&
				data[i] <= 0xfe &&
				data[i+1] >= 0x40 &&
				data[i+1] <= 0xfe &&
				data[i+1] != 0xf7 { 
        
				i += 2
				continue
			} else { 
        
				return false
			}
		}
	}
	return true
}

func preNUm(data byte) int { 
        
	var mask byte = 0x80
	var num int = 0
	//8bit中首个0bit前有多少个1bits
	for i := 0; i < 8; i++ { 
        
		if (data & mask) == mask { 
        
			num++
			mask = mask >> 1
		} else { 
        
			break
		}
	}
	return num
}

func isUtf8(data []byte) bool { 
        
	i := 0
	for i < len(data) { 
        
		if (data[i] & 0x80) == 0x00 { 
        
			// 0XXX_XXXX
			i++
			continue
		} else if num := preNUm(data[i]); num > 2 { 
        
			// 110X_XXXX 10XX_XXXX
			// 1110_XXXX 10XX_XXXX 10XX_XXXX
			// 1111_0XXX 10XX_XXXX 10XX_XXXX 10XX_XXXX
			// 1111_10XX 10XX_XXXX 10XX_XXXX 10XX_XXXX 10XX_XXXX
			// 1111_110X 10XX_XXXX 10XX_XXXX 10XX_XXXX 10XX_XXXX 10XX_XXXX
			// preNUm() 返回首个字节的8个bits中首个0bit前面1bit的个数,该数量也是该字符所使用的字节数
			i++
			for j := 0; j < num-1; j++ { 
        
				//判断后面的 num - 1 个字节是不是都是10开头
				if (data[i] & 0xc0) != 0x80 { 
        
					return false
				}
				i++
			}
		} else { 
        
			//其他情况说明不是utf-8
			return false
		}
	}
	return true
}

结尾

代码可能不是最完美的,但是能实现想要的功能,也感谢各路大神的项目案列,也让自己有了相关代码的参考! 取之于民,用之于民!最后也欢迎各位的指教,共同交流进步!

标签: bt3六盘水仪表变送器

锐单商城拥有海量元器件数据手册IC替代型号,打造 电子元器件IC百科大全!

锐单商城 - 一站式电子元器件采购平台