一个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() //显示打开对话框
    }
}