赞
踩
go get fyne.io/fyne/v2 or go get -u fyne.io/fyne 这两个版本是不一样的建议只装第一个
package main import ( "fyne.io/fyne" "fyne.io/fyne/app" "fyne.io/fyne/widget") func main() { //创建一个窗口 a := app.New() //窗口标题 w := a.NewWindow("hello world!") //写入文本 w.SetContent(widget.NewLabel("Hello world")) //设置窗口大小 w.Resize(fyne.NewSize(200, 200)) //展示窗口 w.ShowAndRun() }
实际上myWin.ShowAndRun()等价于
myWin.Show()
myApp.Run()
myWin.Show()显示窗口,myApp.Run()开启事件循环。
注意一点,fyne默认窗口大小是根据内容的宽高来设置的。上面我们调用myWin.Resize()手动设置了大小。否则窗口只能放下字符串Hello World!。
fyne将功能划分到多个子包中:
fyne.io/fyne:提供所有fyne应用程序代码共用的基础定义,包括数据类型和接口;fyne.io/fyne/app:提供创建应用程序的 API;fyne.io/fyne/canvas:提供Fyne使用的绘制 API;fyne.io/fyne/dialog:提供对话框组件;fyne.io/fyne/layout:提供多种界面布局;fyne.io/fyne/widget:提供多种组件,fyne所有的窗体控件和交互元素都在这个子包中。w := a.NewWindow(“hello world!”)
就从上面hello world中看
//窗口标题
w := a.NewWindow("hello world!")
//设置窗口大小
w.Resize(fyne.NewSize(200, 200))
一个简单的控件,可以用来显示字符串. 类似canvas.Text ,不同之处在于Label可以用来处理简单的格式化问题
package main import ( "fyne.io/fyne/v2" "fyne.io/fyne/v2/app" "fyne.io/fyne/v2/widget") func main() { a := app.New() Mywin := a.NewWindow("Label") Mywin.SetContent(widget.NewLabel("name")) Mywin.Resize(fyne.Size{800, 500}) //设置窗口居中 Mywin.CenterOnScreen() Mywin.ShowAndRun() }
按钮 ,可以让用户点击的. Button可以包含文本,图标.
widget.NewButton()创建一个默认的文本按钮,传入文本和一个无参的回调函数。
带图标的按钮需要调用widget.NewButtonWithIcon(),传入文本和回调参数,还需要一个fyne.Resource类型的图标资源.
package main import ( "fmt" "fyne.io/fyne/theme" "fyne.io/fyne/v2" "fyne.io/fyne/v2/app" "fyne.io/fyne/v2/layout" "fyne.io/fyne/v2/widget") func main() { a := app.New() Mywin := a.NewWindow("test Button") Label := widget.NewLabel("输出:") button1 := widget.NewButton("Button1", func() { fmt.Println("test button ") Label.SetText("button") }) button2 := widget.NewButtonWithIcon("Button2", theme.HomeIcon(), func() { fmt.Println("icon button") Label.SetText("icon Button") }) container := fyne.NewContainerWithLayout(layout.NewVBoxLayout(), button1, button2, Label) Mywin.SetContent(container) Mywin.Resize(fyne.Size{800, 500}) Mywin.CenterOnScreen() Mywin.ShowAndRun() }
一个盒子
其实就是一个简单的水平或垂直的容器.在内部,Box对子控件采用盒状布局
(Box Layout).我们可以通过传入控件对象给widget.NewHBox()或widget.NewVBox()创建盒子。或者调用已经创建好的widget.Box对象的Append()或Prepend()向盒子中添加控件。前者在尾部追加,后者在头部添加。
package main import ( fyne1 "fyne.io/fyne" "fyne.io/fyne/app" widget1 "fyne.io/fyne/widget" ) func main() { a := app.New() Mywin := a.NewWindow("Box test") //在v2版本是没有的 content := widget1.NewVBox( widget1.NewLabel("The top of Vbox"), widget1.NewHBox( widget1.NewLabel("Label 1"), widget1.NewLabel("Lable 2"), ), ) content.Append(widget1.NewButton("Append", func() { content.Append(widget1.NewLabel("Append")) })) content.Append(widget1.NewButton("Prepend", func() { content.Prepend(widget1.NewLabel("Prepended")) })) Mywin.SetContent(content) Mywin.Resize(fyne1.Size{800, 500}) Mywin.CenterOnScreen() Mywin.ShowAndRun() }
注意这其中的版本问题
输入框是用于用户输入简单的文本内容的.调用widget.NewEntry()即可创建一个输入框组件.我们一般保存输入框控件的引用,以便访问其Text字段来获取内容. 注册OnChanged 回调函数. 每当内容有修改的时候, Onchanged就会被调用.我们可以调用SetReadOnly(true)来设置输入框的只读属性 . 方法SetPlaceHolder()用来设置占位字符串,设置字段Multiline让输入框接收多行文本.另外,我们可以使用NewPasswordEntry()创建一个密码输入框,输入的文本是不会以明文显示的.
package main import ( "fmt" "fyne.io/fyne" "fyne.io/fyne/app" "fyne.io/fyne/layout" "fyne.io/fyne/widget") func main() { a := app.New() mywin := a.NewWindow("test Entry") nameentry := widget.NewEntry() nameentry.SetPlaceHolder("input name") nameentry.OnChanged = func(content string) { fmt.Println("name", nameentry.Text, "entry") } passentry := widget.NewPasswordEntry() passentry.SetPlaceHolder("input passwd") nameBox := widget.NewHBox(widget.NewLabel("name"), layout.NewSpacer(), nameentry) passwdBox := widget.NewHBox(widget.NewLabel("password"), layout.NewSpacer(), passentry) loginBtn := widget.NewButton("Login", func() { fmt.Println("name", nameentry.Text, "password", passentry, "login in") }) multiEntry := widget.NewEntry() multiEntry.SetPlaceHolder("please entry\n your description") multiEntry.MultiLine = true content := widget.NewVBox(nameBox, passwdBox, loginBtn, multiEntry) mywin.SetContent(content) mywin.Resize(fyne.Size{800, 500}) mywin.CenterOnScreen() mywin.ShowAndRun() }
package main import ( "fyne.io/fyne" "fyne.io/fyne/app" "fyne.io/fyne/container" "fyne.io/fyne/widget") type App struct { output *widget.Label } var Myapp App func main() { a := app.New() Mywindow := a.NewWindow("Hello world!") //三个组件:输出点,输入点,按钮 output, entry, btn := Myapp.makeUI() //创建一个容器,容器中的VBox填入三个组件 Mywindow.SetContent(container.NewVBox(output, entry, btn)) Mywindow.Resize(fyne.Size{Width: 500, Height: 500}) Mywindow.ShowAndRun() } func (app *App) makeUI() (*widget.Label, *widget.Entry, *widget.Button) { output := widget.NewLabel("Hello world!") entry := widget.NewEntry() btn := widget.NewButton("Enter", func() { app.output.SetText(entry.Text) }) app.output = output //高亮按钮(让按钮变得重要,按钮会变成蓝色) btn.Importance = widget.HighImportance return output, entry, btn }
窗口雏形
package main import ( "fyne.io/fyne/v2" "fyne.io/fyne/v2/app" "fyne.io/fyne/v2/container" "fyne.io/fyne/v2/widget") type config struct { EditWidget *widget.Entry //编辑窗口 PreviewWidget *widget.RichText //预览窗口,RichText是一个富文本编辑器 CurrentFile fyne.URI //当前的文件 SaveMenuItem *fyne.MenuItem //文件保存的菜单 } var cfg config func main() { //创建一个fyneAPP a := app.New() // 给这个APP创建一个窗口 win := a.NewWindow("Markdown") //拿到用户的接口 edit, preview := cfg.MakeUI() // 设置窗口的内容 win.SetContent(container.NewHSplit(edit, preview)) //展示窗口并启动应用 win.Resize(fyne.Size{Width: 800, Height: 500}) //窗口居中 win.CenterOnScreen() win.ShowAndRun() } func (app config) MakeUI() (*widget.Entry, *widget.RichText) { // 这个函数会返回Markdown的编辑页面和预览页面 // 创建一个多行的编辑组件 edit := widget.NewMultiLineEntry() //创建预览窗口组件 preview := widget.NewRichTextFromMarkdown("") app.EditWidget = edit app.PreviewWidget = preview edit.OnChanged = preview.ParseMarkdown return edit, preview }

添加菜单

这是成品
看看代码:
cfg.CreateMenuItem(win)
调用创建菜单函数
// 创建菜单项 func (app config) CreateMenuItem(win fyne.Window) { //打开菜单项 openMenuItem := fyne.NewMenuItem("Open..", func() { }) //保存菜单项 saveMenuItem := fyne.NewMenuItem("save", func() { }) //保存为菜单项,也就是另存为. saveAsMenuItem := fyne.NewMenuItem("save as .....", func() { }) // 创建一个菜单: fileMenu := fyne.NewMenu("File", openMenuItem, saveMenuItem, saveAsMenuItem) // 表示文件菜单有三个选项 menu := fyne.NewMainMenu(fileMenu) // 设置主菜单 win.SetMainMenu(menu) }
可以看见NewMenuItem是创建展开后的小项,NewMenu是创建一个在菜单栏中可以看见点击的菜单.
可以看到在菜单项中的函数没有内容,想想就知道,这里写的内容就是点击了之后产生的操作.
//打开菜单
openMenuItem := fyne.NewMenuItem("Open..", func() {
})
//保存菜单
saveMenuItem := fyne.NewMenuItem("save", func() {
})
//保存为菜单
saveAsMenuItem := fyne.NewMenuItem("save as .....", func() {
})
接着就是写这里的内容了
不过为了保持代码整洁,我可以把这三个函数写在外面.用的时候调用就行.
//过滤只能打开md文件 var filter = storage.NewExtensionFileFilter([]string{".md", ".MD"}) func (app *config) saveFunc(win fyne.Window) func() { return func() { //当前文件不是空的时候才可以保存 if app.CurrentFile != nil { writer, err := storage.Writer(app.CurrentFile) if err != nil { dialog.ShowError(err, win) return } writer.Write([]byte(app.EditWidget.Text)) defer writer.Close() } } } // 创建一个返回值是函数的方法. func (app *config) saveAsFunc(win fyne.Window) func() { // fyne是跨平台的,在保存文件的时候,不需要考虑操作系统的区别. return func() { saveDialog := dialog.NewFileSave(func(write fyne.URIWriteCloser, err error) { //出现错误就直接返回,错误处理模块 if err != nil { dialog.ShowError(err, win) return } if write == nil { // 用户点击了取消保存 return } if !strings.HasSuffix(strings.ToLower(write.URI().String()), ".md") { dialog.ShowInformation("error", "please name your file with a .md extension", win) return } //保存文件 _, err = write.Write([]byte(app.EditWidget.Text)) if err != nil { return } app.CurrentFile = write.URI() defer func(write fyne.URIWriteCloser) { err := write.Close() if err != nil { } }(write) //保存文件后就来改变下窗口的Title win.SetTitle(win.Title() + "-" + write.URI().Name()) app.SaveMenuItem.Disabled = false }, win) //设置默认文件名 saveDialog.SetFileName("untitled.md") //设置文件后缀过滤 saveDialog.SetFilter(filter) //展示出来 saveDialog.Show() } } //打开文件的函数编写. func (app *config) openFunc(win fyne.Window) func() { return func() { openDialog := dialog.NewFileOpen(func(read fyne.URIReadCloser, err error) { if err != nil { dialog.ShowError(err, win) return } if read == nil { return } defer read.Close() data, err := ioutil.ReadAll(read) if err != nil { dialog.ShowError(err, win) return } app.EditWidget.SetText(string(data)) app.CurrentFile = read.URI() win.SetTitle(win.Title() + "-" + read.URI().Name()) app.SaveMenuItem.Disabled = false }, win) //设置过滤 openDialog.SetFilter(filter) openDialog.Show() } }
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。