一个fyne的简易Markdown代码
package main // 主程序包
import (
"io"
"os"
"fyne.io/fyne/v2"
"fyne.io/fyne/v2/app" // 导入Fyne应用包
"fyne.io/fyne/v2/container"
"fyne.io/fyne/v2/dialog"
"fyne.io/fyne/v2/storage"
"fyne.io/fyne/v2/widget" // 导入Fyne部件包
)
// 初始化
func init() {
os.Setenv("FYNE_FONT", "font.otf") // 设置环境变量
}
// 定义部件的类
type config struct {
EditWidget *widget.Entry //左边编辑窗口
PreviewWidget *widget.RichText //右边显示窗口
CurrentFile fyne.URI //文件浏览器
SaveMenuItem *fyne.MenuItem //保存
}
var cfg config
// 部件逻辑
func (app *config) makeUI() (*widget.Entry, *widget.RichText) { //要设置输出的每个部件和指针类型
edit := widget.NewMultiLineEntry()
preview := widget.NewRichTextFromMarkdown("")
app.EditWidget = edit
app.PreviewWidget = preview
edit.OnChanged = preview.ParseMarkdown //将edit的变换响应 去执行preview的ParseMarkdown放置方法,他会自动取得edit内容
return edit, preview //返回部件信息
}
func main() {
a := app.New()
w := a.NewWindow("笔记软件") // 创建一个新窗口"
edit, preview := cfg.makeUI() //获取部件
cfg.createMenuItems(w) //创建菜单传入参数是窗口对象
w.SetContent(container.NewHSplit(edit, preview)) // 放入HSplit左右分屏容器
w.Resize(fyne.Size{Width: 800, Height: 500}) //界面大小
w.CenterOnScreen() //窗口居中
w.ShowAndRun() // 显示窗口并运行应用程序
}
// 创建菜单
func (app *config) createMenuItems(w fyne.Window) { //创建菜单函数
openMenuItem := fyne.NewMenuItem("打开..", app.openFunc(w)) //创建子菜单“打开”
saveMenuItem := fyne.NewMenuItem("保存", app.saveFunc(w)) //创建子带单“保存”
app.SaveMenuItem = saveMenuItem //将“保存” 给予结构体共享变量
app.SaveMenuItem.Disabled = false //显示菜单“保存”显示
saveAsMenuItem := fyne.NewMenuItem("另存为", app.saveAsFunc(w)) //创建子菜单“另存为” ,执行函数saveAsFunc
fileMenu := fyne.NewMenu("文件", openMenuItem, saveMenuItem, saveAsMenuItem) //添加菜单1,将子菜单包裹
menu := fyne.NewMainMenu(fileMenu) //创建菜单,添加菜单2
w.SetMainMenu(menu) //添加菜单3,将菜单设置到窗口
}
// 另存为
func (app *config) saveAsFunc(w fyne.Window) func() { //创建了一个另存为结构体函数, 使用windows参数,返回匿名函数
return func() { //返回一个匿名函数
//创建一个NewFileSave文件保存对话框,如果得到用户回调后它会执行参数中的函数
//并传递fyne.URIWriteCloser文件写入接口,和一个err错误类型
saveDialog := dialog.NewFileSave(func(write fyne.URIWriteCloser, err error) {
if err != nil { //如果出现错误
dialog.ShowError(err, w) //弹出错误对话框
return
}
if write == nil {
return //如果write没有任何数据,有可能是用户取消了保存,则什么也不做
}
//如果没有遇到错误,则开始保存文件
write.Write([]byte(app.EditWidget.Text))
app.CurrentFile = write.URI() //将当前操作文件设置为 保存文件后的RUI
defer write.Close() //关闭write接口
w.SetTitle(w.Title() + "-" + write.URI().Name()) //修改窗口标题,也就是保存的文件名
// app.SaveMenuItem.Disabled = true //将菜单的“保存”隐藏
}, w)
saveDialog.Show() //显示文件保存对话框
}
}
// 保存,此功能只会保存已经存在的路径,不会执行浏览文件的窗口
func (app *config) saveFunc(w fyne.Window) func() {
// 创建一个 saveFunc 函数,接收 fyne.Window 参数并返回一个匿名函数
return func() {
// 返回一个匿名函数,该函数在调用时执行以下操作
if app.CurrentFile != nil {
// 如果 CurrentFile 不为空,表示已经有打开的文件记录
write, err := storage.Writer(app.CurrentFile)
// 使用 storage.Writer 打开当前文件的写入器,返回一个写入流和可能的错误
if err != nil {
dialog.ShowError(err, w)
// 如果打开写入器时出现错误,显示错误对话框并返回
return
}
write.Write([]byte(app.EditWidget.Text))
// 将 EditWidget 中的文本内容写入到文件中
defer write.Close()
// 确保在函数结束时关闭写入流
}
}
}
// 打开文件
func (app *config) openFunc(w fyne.Window) func() { //创建了一个另存为结构体函数, 使用windows参数,然后执行后面的匿名函数
return func() { //再返回一个匿名函数
//创建一个NewFileOpen打开文件对话框,如果得到用户回调后它会执行参数中的函数
//并传递fyne.RIReadCloser文件打开接口,和一个err错误类型
openDialog := dialog.NewFileOpen(func(read fyne.URIReadCloser, err error) {
if err != nil { //如果出现错误
dialog.ShowError(err, w) //弹出错误对话框
return
}
if read == nil {
return //如果read没有任何数据,有可能是用户取消了打开文件,则什么也不做
}
defer read.Close() //关闭read接口
data, err := io.ReadAll(read) //打开文件
if err != nil {
dialog.ShowError(err, w) //如果文件打开错误则弹出错误对话
return
}
//如果打开没有错误,则将编辑框设置内容为读取的内容
app.EditWidget.SetText(string(data))
app.CurrentFile = read.URI() //将当前编辑文件指向当前路径
w.SetTitle(w.Title() + "-" + read.URI().Name()) //将标题设置为文件文件名
app.SaveMenuItem.Disabled = false //显示“保存”菜单
}, w)
openDialog.Show() //显示打开对话框
}
}