youtbe_download

什么是fyne

fyne是为go语言开发跨平台的图形化应用程序出的一个工具包,通过fyne可以用go语言开发出兼容Mac OS、Linux、Windows、Android、IOS的应用程序。这篇文章只是一个简单的入门教程,如果想看详细的介绍,可以关注fyne的官网

image-20220703105339142

创建go工程

1
mkdir fyne_sample
1
2
cfp@cfp:~/program/go/fyne_sample$ go mod init fyne_sample
go: creating new go.mod: module fyne_sample
1
cfp@cfp:~/program/go/fyne_sample$ go get fyne.io/fyne/v2
1
cfp@cfp:~/program/go/fyne_sample$ go mod tidy

Hello World

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
package main

import (
	"fyne.io/fyne/v2/app"
	"fyne.io/fyne/v2/widget"
)

func main() {
	a := app.New()
	w := a.NewWindow("Hello World!")
	w.SetContent(widget.NewLabel("Hello World!"))
	w.ShowAndRun()

}

应用和RunLoop

RunLoop就是程序在循环过程中处理各种事件,比如说触摸事件、UI刷新事件、定时器事件、Selector事件,从而保持程序的持续运行。

更新控件内容

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
func main() {
	a := app.New()
	w := a.NewWindow("Hello World!")

	clock := widget.NewLabel("")
	w.SetContent(clock)

	formatted := time.Now().Format("Time: 03:04:05")
	clock.SetText(formatted)

	w.ShowAndRun()
}

image-20220528090219442

后台运行

如果你做过app开发,都直到如果你的程序有耗时任务时,需要将其放到后台执行,或者一个单独的线程去执行,不能直接在UI线程中执行,否则会阻塞UI线程,出现卡顿的情况。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
func updateTime(clock *widget.Label) {
	formatted := time.Now().Format("Time: 03:04:05")
	clock.SetText(formatted)
}

func main() {
	a := app.New()
	w := a.NewWindow("Hello World!")

	clock := widget.NewLabel("")
	w.SetContent(clock)

	go func() {
		for range time.Tick(time.Second) {
			updateTime(clock)
		}
	}()

	w.ShowAndRun()

}

image-20220528091422752

显示两个窗口

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
func main() {
	a := app.New()
	w := a.NewWindow("Hello World!")
	w.Resize(fyne.NewSize(500, 500))
	w.SetContent(widget.NewLabel("Hello World!"))
	w.Show()

	w2 := a.NewWindow("Clock")
	w2.Resize(fyne.NewSize(500, 500))

	clock := widget.NewLabel("")
	w2.SetContent(clock)

	go func() {
		for range time.Tick(time.Second) {
			updateTime(clock)
		}
	}()

	w2.Show()
	a.Run()
}

image-20220528094842456

通过一个窗口打开另外一个窗口

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
func main() {
	a := app.New()
	w := a.NewWindow("Hello World!")
	w.Resize(fyne.NewSize(500, 500))
	w.SetContent(widget.NewLabel("Hello World!"))
	w.Show()

	w2 := a.NewWindow("Clock")
	w2.Resize(fyne.NewSize(500, 500))

	clock := widget.NewLabel("")
	w2.SetContent(clock)

	go func() {
		for range time.Tick(time.Second) {
			updateTime(clock)
		}
	}()

	w2.Show()

	w2.SetContent(widget.NewButton("Open new", func() {
		w3 := a.NewWindow("window 3")
		w3.SetContent(widget.NewLabel("window 3"))
		w3.Resize(fyne.NewSize(500, 500))
		w3.Show()
	}))

	a.Run()
}

image-20220528095435141

打包

打包就是根据不同的平台,生产对应的可执行文件。

首先要安装fyne

1
go install fyne.io/fyne/v2/cmd/fyne

然后在工程目录执行

1
fyne package -os linux -icon logo.png

这样就会生产一个打包文件 fyne_sample.tar.xz

解压之后执行make就可以进行安装了。

Canvas和CanvasObject

填充颜色

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
func main() {
	myApp := app.New()
	myWindow := myApp.NewWindow("Canvas")
	myCanvas := myWindow.Canvas()
	blue := color.NRGBA{R: 0, G: 0, B: 180, A: 255}
	rect := canvas.NewRectangle(blue)
	myCanvas.SetContent(rect)

	go func() {
		time.Sleep(time.Second)
		green := color.NRGBA{R: 0, G: 180, B: 0, A: 255}
		rect.FillColor = green
		rect.Refresh()
	}()
	myWindow.Resize(fyne.NewSize(500, 500))
	myWindow.ShowAndRun()
}

image-20220528153954812

文字和圆形

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
func main() {
	myApp := app.New()
	myWindow := myApp.NewWindow("Canvas")
	myCanvas := myWindow.Canvas()
	blue := color.NRGBA{R: 0, G: 0, B: 180, A: 255}
	rect := canvas.NewRectangle(blue)
	myCanvas.SetContent(rect)

	go func() {
		time.Sleep(time.Second)
		green := color.NRGBA{R: 0, G: 180, B: 0, A: 255}
		rect.FillColor = green
		rect.Refresh()
	}()
	setContentText(myCanvas)
	setContentToCircle(myCanvas)
	myWindow.Resize(fyne.NewSize(500, 500))
	myWindow.ShowAndRun()
}

func setContentText(c fyne.Canvas) {

	green := color.NRGBA{R: 0, G: 180, B: 0, A: 255}
	text := canvas.NewText("Text", green)
	text.TextStyle.Bold = true
	c.SetContent(text)
}

func setContentToCircle(c fyne.Canvas) {
	red := color.NRGBA{R: 180, G: 0, B: 0, A: 255}
	circle := canvas.NewCircle(red)
	circle.StrokeWidth = 4
	circle.FillColor = red
	c.SetContent(circle)

}

Widget

一个Widget是一个特殊的Canvas,一个Window可以设置一个单独的Widget.

1
2
3
4
5
6
7
func main() {
	myApp := app.New()
	myWindow := myApp.NewWindow("Widget")
	myWindow.SetContent(widget.NewEntry())
	myWindow.Resize(fyne.NewSize(500, 500))
	myWindow.ShowAndRun()
}

Container和Layouts

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
func main() {
	myApp := app.New()
	myWindow := myApp.NewWindow("Container")
	green := color.NRGBA{R: 0, G: 180, B: 0, A: 255}
	text1 := canvas.NewText("Hello", green)
	text2 := canvas.NewText("There", green)
	text2.Move(fyne.NewPos(20, 20))
	content := container.NewWithoutLayout(text1, text2)
	myWindow.SetContent(content)
	myWindow.Resize(fyne.NewSize(500, 500))
	myWindow.ShowAndRun()
}

AppTabs

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
func main() {
	// scr := gui.InitNewScreen()
	// gui.Start(scr)

	myApp := app.New()
	myWindow := myApp.NewWindow("TabContainer Widget")

	text1 := canvas.NewText("1", color.White)
	text2 := canvas.NewText("2", color.White)
	text3 := canvas.NewText("3", color.White)
	grid := container.New(layout.NewGridLayout(2), text1, text2, text3)

	tabs := container.NewAppTabs(
		container.NewTabItem("Tab 1", grid),
		container.NewTabItem("Tab 2", widget.NewLabel("World!")),
	)

	//tabs.Append(container.NewTabItemWithIcon("Home", theme.HomeIcon(), widget.NewLabel("Home tab")))

	tabs.SetTabLocation(container.TabLocationLeading)

	myWindow.SetContent(tabs)
	myWindow.ShowAndRun()
}

image-20220529072951498

Button

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
func main() {
	// scr := gui.InitNewScreen()
	// gui.Start(scr)

	myApp := app.New()
	myWindow := myApp.NewWindow("Button Widget")

	content := widget.NewButton("click me", func() {
		showWindow2(myApp)
	})

	//content := widget.NewButtonWithIcon("Home", theme.HomeIcon(), func() {
	//	log.Println("tapped home")
	//})

	myWindow.SetContent(content)
	myWindow.ShowAndRun()
}

func showWindow2(app fyne.App) {
	myWindow2 := app.NewWindow("Button Widget 2")
	text := canvas.NewText("window2", color.White)
	myWindow2.SetContent(text)
	myWindow2.Show()
}

image-20220529073916713

Entry(输入框)

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
func main() {
	// scr := gui.InitNewScreen()
	// gui.Start(scr)

	myApp := app.New()
	myWindow := myApp.NewWindow("Entry Widget")

	input := widget.NewEntry()
	input.SetPlaceHolder("Enter text...")

	content := container.NewVBox(input, widget.NewButton("Save", func() {
		log.Println("Content was:", input.Text)
	}), widget.NewButton("Cancel", func() {
		log.Println("Content was cancel:", input.Text)
	}))

	myWindow.SetContent(content)
	myWindow.ShowAndRun()
}

image-20220529074435577

选择框

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
func main() {
	// scr := gui.InitNewScreen()
	// gui.Start(scr)

	myApp := app.New()
	myWindow := myApp.NewWindow("Choice Widgets")

	check := widget.NewCheck("Optional", func(value bool) {
		log.Println("Check set to", value)
	})
	radio := widget.NewRadioGroup([]string{"Option 1", "Option 2"}, func(value string) {
		log.Println("Radio set to", value)
	})
	combo := widget.NewSelect([]string{"Option 1", "Option 2"}, func(value string) {
		log.Println("Select set to", value)
	})

	myWindow.SetContent(container.NewVBox(check, radio, combo))
	myWindow.ShowAndRun()
}

image-20220529101348693

表单提交

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
func main() {
	// scr := gui.InitNewScreen()
	// gui.Start(scr)

	myApp := app.New()
	myWindow := myApp.NewWindow("Form Widget")

	entry := widget.NewEntry()
	textArea := widget.NewMultiLineEntry()

	form := &widget.Form{
		Items: []*widget.FormItem{ // we can specify items in the constructor
			{Text: "Entry", Widget: entry}},
		OnSubmit: func() { // optional, handle form submission
			log.Println("Form submitted:", entry.Text)
			log.Println("multiline:", textArea.Text)
			myWindow.Close()
		},
	}

	// we can also append items
	form.Append("Text", textArea)

	myWindow.SetContent(form)
	myWindow.ShowAndRun()
}

image-20220529102116087

进度条

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
func main() {
	// scr := gui.InitNewScreen()
	// gui.Start(scr)

	myApp := app.New()
	myWindow := myApp.NewWindow("ProgressBar Widget")

	progress := widget.NewProgressBar()
	infinite := widget.NewProgressBarInfinite()

	go func() {
		for i := 0.0; i <= 1.0; i += 0.5 {
			time.Sleep(time.Millisecond * 3000)
			progress.SetValue(i)
			progress.Hide()
			infinite.Hide()
		}
	}()

	myWindow.SetContent(container.NewVBox(progress, infinite))
	myWindow.ShowAndRun()
}

image-20220529103120708