通过示例学习 Go:第 7 部分 - 使用 Go 创建跨平台 GUI/桌面应用程序
在之前的文章中,我们创建了一个HTTP REST API 服务器、一个CLI、一个Discord 机器人,甚至还创建了一个 Nintendo Game Boy Advance 游戏。
Golang 大量用于 CLI 和微服务,但如何创建 GUI/桌面和移动应用程序呢?
初始化
我们在上一篇文章中创建了Git 存储库,因此现在我们只需要在本地检索它:
$ git clone https://github.com/scraly/learning-go-by-examples.git
$ cd learning-go-by-examples
我们将为go-gopher-desktop
我们的 CLI 应用程序创建一个文件夹并进入该文件夹:
$ mkdir go-gopher-desktop
$ cd go-gopher-desktop
现在,我们必须初始化 Go 模块(依赖管理):
$ go mod init github.com/scraly/learning-go-by-examples/go-gopher-desktop
go: creating new go.mod: module github.com/scraly/learning-go-by-examples/go-gopher-desktop
这将创建一个go.mod
如下文件:
module github.com/scraly/learning-go-by-examples/go-gopher-desktop
go 1.16
在开始编写桌面应用程序代码之前,作为良好的做法,我们将创建一个简单的代码组织。
创建以下文件夹组织:
.
├── README.md
└── go.mod
就这样?是的,我们剩下的代码组织很快就会创建完成 ;-)。
费恩
Fyne是一款用于构建桌面和移动应用程序的 UI 工具包。其界面设计遵循Material Design原则,提供跨平台的图形,在所有支持的平台上均显示相同的效果。
图形应用程序的创建通常比基于 Web 或命令行的应用程序更复杂。Fyne 利用 Go 的优秀设计改变了这一现状,使构建美观的图形应用程序变得简单快捷。
Fyne 工具包支持为 iOS 和 Android 设备以及 macOS、Windows、Linux 和 BSD 构建。
有了 Fyne,无需了解 React、Angular 或 VueJS 框架,我们就可以使用我们最喜欢的语言 Go 创建 GUI 和移动应用程序 ;-)。
Fyne 提供了可执行文件和依赖项。
为了使用 Fyne,我们首先需要安装fyne
可执行命令:
$ go get fyne.io/fyne/v2/cmd/fyne
然后是它的依赖项:
$ go get fyne.io/fyne/v2
此时,该go.mod
文件应该具有以下导入:
module github.com/scraly/learning-go-by-examples/go-gopher-desktop
go 1.16
require (
fyne.io/fyne/v2 v2.0.4 // indirect
)
让我们创建我们的桌面应用程序!
我们想要什么?
我们希望创建一个适用于桌面/GUI 和移动设备的应用程序来显示:
- 菜单
- 文本
- 一只可爱的随机地鼠
- 随机按钮
让我们创建一个main.go
文件。
我们初始化名为main 的包,以及我们需要导入的所有依赖项/库:
package main
import (
"image/color"
"fyne.io/fyne/v2"
"fyne.io/fyne/v2/app"
"fyne.io/fyne/v2/canvas"
"fyne.io/fyne/v2/container"
"fyne.io/fyne/v2/dialog"
"fyne.io/fyne/v2/widget"
)
定义我们的常数:
const KuteGoAPIURL = "https://kutego-api-xxxxx-ew.a.run.app"
然后,创建我们的main()
函数:
func main() {
myApp := app.New()
myWindow := myApp.NewWindow("Gopher")
// Main menu
fileMenu := fyne.NewMenu("File",
fyne.NewMenuItem("Quit", func() { myApp.Quit() }),
)
helpMenu := fyne.NewMenu("Help",
fyne.NewMenuItem("About", func() {
dialog.ShowCustom("About", "Close", container.NewVBox(
widget.NewLabel("Welcome to Gopher, a simple Desktop app created in Go with Fyne."),
widget.NewLabel("Version: v0.1"),
widget.NewLabel("Author: Aurélie Vache"),
), myWindow)
}))
mainMenu := fyne.NewMainMenu(
fileMenu,
helpMenu,
)
myWindow.SetMainMenu(mainMenu)
// Define a welcome text centered
text := canvas.NewText("Display a random Gopher!", color.White)
text.Alignment = fyne.TextAlignCenter
// Define a Gopher image
var resource, _ = fyne.LoadResourceFromURLString(KuteGoAPIURL + "/gopher/random/")
gopherImg := canvas.NewImageFromResource(resource)
gopherImg.SetMinSize(fyne.Size{Width: 500, Height: 500}) // by default size is 0, 0
// Define a "random" button
randomBtn := widget.NewButton("Random", func() {
resource, _ := fyne.LoadResourceFromURLString(KuteGoAPIURL + "/gopher/random/")
gopherImg.Resource = resource
//Redrawn the image with the new path
gopherImg.Refresh()
})
randomBtn.Importance = widget.HighImportance
// Display a vertical box containing text, image and button
box := container.NewVBox(
text,
gopherImg,
randomBtn,
)
// Display our content
myWindow.SetContent(box)
// Close the App when Escape key is pressed
myWindow.Canvas().SetOnTypedKey(func(keyEvent *fyne.KeyEvent) {
if keyEvent.Name == fyne.KeyEscape {
myApp.Quit()
}
})
// Show window and run app
myWindow.ShowAndRun()
}
让我们一步一步解释一下主要功能。
首先,我们创建一个新的应用程序和一个新窗口,标题为“Gopher”:
myApp := app.New()
myWindow := myApp.NewWindow("Gopher")
要使图形应用程序正常工作,我们首先需要创建一个新的应用程序和一个窗口。因此,我们创建一个包含单个窗口的新应用程序,其标题为“Gopher”。
然后,我们创建一个主菜单:
// Main menu
fileMenu := fyne.NewMenu("File",
fyne.NewMenuItem("Quit", func() { myApp.Quit() }),
)
helpMenu := fyne.NewMenu("Help",
fyne.NewMenuItem("About", func() {
dialog.ShowCustom("About", "Close", container.NewVBox(
widget.NewLabel("Welcome to Gopher, a simple Desktop app created in Go with Fyne."),
widget.NewLabel("Version: v0.1"),
widget.NewLabel("Author: Aurélie Vache"),
), myWindow)
}))
mainMenu := fyne.NewMainMenu(
fileMenu,
helpMenu,
)
myWindow.SetMainMenu(mainMenu)
主菜单包含文件和帮助菜单:
├── File
│ └── Quit
└── Help
└── About
当我们点击“文件”>“退出”时,应用程序将退出。
当我们点击“帮助”>“关于”时,将显示一个带有“关于”文本的对话框。
在窗口内,我们放置一个文本“显示一个随机的 Gopher!”并将其居中。
// Define a welcome text centered
text := canvas.NewText("Display a random Gopher!", color.White)
text.Alignment = fyne.TextAlignCenter
现在是时候定义我们可爱的 Gopher 形象了:
// Define a Gopher image
var resource, _ = fyne.LoadResourceFromURLString(KuteGoAPIURL + "/gopher/random/")
gopherImg := canvas.NewImageFromResource(resource)
gopherImg.SetMinSize(fyne.Size{Width: 500, Height: 500}) // by default size is 0, 0
为此,我们从 KuteGo API 随机 URL 在内存中创建一个新的 StaticResource,我们将其定义为图像的资源,并设置图像的最小尺寸。
哦,对了,空白标识符 _
是一个匿名占位符。它可以像变量声明中的其他标识符一样使用,但它不会引入绑定。
在这种情况下,函数LoadResourceFromURLString
会返回一个资源和一个错误,但我不想检索错误、测试错误并在发生错误时执行某些操作。所以我用“_
我不关心”来代替这个值。
我建议您检索错误并在发生错误时采取一些措施,但对于这个例子,我想向您展示这个 Golang 功能 :-)。
让我们回到我们的main()
函数。
然后,我们定义一个带有“随机”文本的按钮,颜色为蓝色(高重要性级别)。
当我们点击此按钮时,我们需要检索一个新的随机 Gopher,并将其定义为图像的资源。并且我们需要刷新图像,以便告诉 Fyne 重新绘制它。
// Define a "random" button
randomBtn := widget.NewButton("Random", func() {
resource, _ := fyne.LoadResourceFromURLString(KuteGoAPIURL + "/gopher/random/")
gopherImg.Resource = resource
//Redrawn the image with the new path
gopherImg.Refresh()
})
randomBtn.Importance = widget.HighImportance
得益于新的图像资源和刷新方法,屏幕将更新给最终用户。
之后,我们用三个元素定义一个垂直框并将其设置到我们的窗口中:
// Display a vertical box containing text, image and button
box := container.NewVBox(
text,
gopherImg,
randomBtn,
)
// Display our content
myWindow.SetContent(box)
垂直框布局将项目按列排列。每个项目的高度设置为最小值,所有项目的宽度均相等,设置为最小宽度中的最大值。
我们监听用户按下键盘上的Esc键,然后关闭应用程序。
最后,我们运行应用程序并显示窗口。
// Close the App when Escape key is pressed
myWindow.Canvas().SetOnTypedKey(func(keyEvent *fyne.KeyEvent) {
if keyEvent.Name == fyne.KeyEscape {
myApp.Quit()
}
})
// Show window and run app
myWindow.ShowAndRun()
该方法是和 的Window.ShowAndRun()
快捷方式。Window.Show()
App.Run()
调用myApp.Run()
或之后myWindow.ShowAndRun()
,我们的应用程序将运行,并且函数将在窗口关闭后返回。
测试一下!
现在是时候测试我们的第一个图形应用程序了,为此我们将运行它:
$ go run main.go
太棒了,我们的桌面应用程序正在运行!
我们可以点击“随机”按钮,另一只可爱的地鼠就会出现:-)。
我们可以点击“帮助”>“关于”菜单来显示我们的关于信息:
我们也可以按下键盘上的Esc键,应用程序就会退出 ;-)。
太好了,我们的小桌面应用程序运行正常!
作为移动设备进行测试
您是否知道我们还可以在移动环境中测试应用程序并进行模拟?
使用以下命令,我们将看到我们的应用程序如何在移动设备上运行:
$ go run -tags mobile main.go
或者通过我们的任务:
$ task run-mobile
task: [run-mobile] GOFLAGS=-mod=mod go run -tags mobile main.go
如您所见,菜单的显示与 GUI/桌面应用程序中的不同。
建造/打包它!
我们的应用程序现在已经准备好了,只需构建它。
为此,与之前的文章一样,我们将使用Taskfile来自动执行常见任务。
因此,对于这个应用程序,我也创建了一个Taskfile.yml
包含以下内容的文件:
version: "3"
tasks:
run:
desc: Run the app
cmds:
- GOFLAGS=-mod=mod go run main.go
run-mobile:
desc: Run the app on mobile emulator
cmds:
- GOFLAGS=-mod=mod go run -tags mobile main.go
build:
desc: Build the app for current OS
cmds:
# - GOFLAGS=-mod=mod go build -o bin/gopher-desktop main.go
- fyne package -icon gopher.png
package-android:
desc: Package the app for Android
cmds:
- fyne package -os android -appID com.scraly.gopher -icon gopher.png
package-ios:
desc: Package the app for iOS
cmds:
- fyne package -os ios -appID com.scraly.gopher -icon gopher.png
有了这些,我们可以轻松地构建应用程序。在执行任务之前,让我们先解释一下 GUI 和移动应用程序的打包。
为多个操作系统打包可能是一项复杂的任务。图形应用程序通常具有与其关联的图标和元数据,以及与每个环境集成所需的特定格式。
该fyne
命令支持准备在工具包支持的所有平台上分发的应用程序。运行该fyne package
命令将创建一个应用程序,该应用程序可安装在一台计算机上,并且只需从当前目录复制创建的文件即可分发到其他计算机。
让我们构建/打包它:
$ task package
task: [package] fyne package -icon gopher.png
此命令会为当前操作系统创建一个嵌入图标的应用程序。
我使用的是 MacOS,因此以下命令会为其生成一个应用程序:
双击它时,桌面应用程序将启动,并带有我们可爱的图标:
task package
如果您在 Windows 环境中运行命令,您将获得一个.exe
可执行文件。
在 MacOS 计算机上,您将获得一个.app
软件包(如本文所示)。
对于 Linux,您将获得一个.tar.xz
可以按常规方式安装的文件(或者在解压的文件夹中运行 make install)。
您还可以指定目标操作系统,如下所示:
$ fyne package -os windows -icon myapp.png
...并将其打包为 Android 和 iOS!
要在真实的移动设备上运行,需要打包应用程序。为此,我们可以使用该fyne package
命令。
让我们为 Android 打包我们的应用程序:
$ fyne package -os android -appID com.scraly.gopher -icon gopher.png
或者执行我们的任务:
$ task package-android
task: [package-android] fyne package -os android -appID com.scraly.gopher -icon gopher.png
我们也可以对 iOS 做同样的事情:
$ task package-ios
task: [package-ios] fyne package -os ios -appID com.scraly.gopher -icon gopher.png
/!\ 警告:为了打包 Android 版本,您需要adb
在电脑上安装 ;为了打包 iOS 版本,您需要安装XCode
。请阅读以下说明。
如果您不安装它们,您将收到以下错误消息:
安卓:
$ task package-android
task: [package-android] fyne package -os android -appID com.scraly.gopher -icon gopher.png
no Android NDK found in $ANDROID_HOME/ndk-bundle nor in $ANDROID_NDK_HOME
task: Failed to run task "package-android": exit status 1
iOS:
$ task package-ios
task: [package-ios] fyne package -os ios -appID com.scraly.gopher -icon gopher.png
-os=ios requires XCode
task: Failed to run task "package-ios": exit status 1
發佈它!
我们运行它、测试它、构建它、打包它,那么现在最后一步是什么呢?我们可以分发我们的应用程序!
众所周知,在 Play 和 App Store 上分发我们的应用非常麻烦。正因如此,我们fyne release
才有了命令。
只需一个命令,您就可以将您的应用捆绑到 Play 商店:
$ fyne release -os android -appID com.example.myapp -appVersion 1.0 -appBuild 1
如果您有兴趣分发您的应用程序,请遵循完整的说明。
结论
正如我们在本文中看到的,使用Fyne可以在几分钟内创建一个简单的 GUI/桌面和移动应用程序。
特别感谢在Slack上帮助我的Andrew Williams。
但是,要小心,我不建议您使用 Go 开发所有 Web 应用程序、REST、gRPC、游戏、移动设备(...)和桌面应用程序,但我认为了解您可以这样做以及具体如何做到这一点很有趣:-)。
所有代码均可在以下位置找到: https: //github.com/scraly/learning-go-by-examples/tree/main/go-gopher-desktop
文章来源:https://dev.to/aurelievache/learning-go-by-examples-part-7-create-a-cross-platform-gui-desktop-app-in-go-44j1