通过示例学习 Go:第 7 部分 - 使用 Go 创建跨平台 GUI/桌面应用程序

2025-06-04

通过示例学习 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


Enter fullscreen mode Exit fullscreen mode

我们将为go-gopher-desktop我们的 CLI 应用程序创建一个文件夹并进入该文件夹:



$ mkdir go-gopher-desktop
$ cd go-gopher-desktop


Enter fullscreen mode Exit fullscreen mode

现在,我们必须初始化 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


Enter fullscreen mode Exit fullscreen mode

这将创建一个go.mod如下文件:



module github.com/scraly/learning-go-by-examples/go-gopher-desktop

go 1.16


Enter fullscreen mode Exit fullscreen mode

在开始编写桌面应用程序代码之前,作为良好的做法,我们将创建一个简单的代码组织。

创建以下文件夹组织:



.
├── README.md
└── go.mod


Enter fullscreen mode Exit fullscreen mode

就这样?是的,我们剩下的代码组织很快就会创建完成 ;-)。

费恩

费恩

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


Enter fullscreen mode Exit fullscreen mode

然后是它的依赖项:



$ go get fyne.io/fyne/v2


Enter fullscreen mode Exit fullscreen mode

此时,该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
)


Enter fullscreen mode Exit fullscreen mode

让我们创建我们的桌面应用程序!

星光SG1地鼠

我们想要什么?

我们希望创建一个适用于桌面/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"
)


Enter fullscreen mode Exit fullscreen mode

定义我们的常数:



const KuteGoAPIURL = "https://kutego-api-xxxxx-ew.a.run.app"


Enter fullscreen mode Exit fullscreen mode

然后,创建我们的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()
}


Enter fullscreen mode Exit fullscreen mode

让我们一步一步解释一下主要功能。

首先,我们创建一个新的应用程序和一个新窗口,标题为“Gopher”:



    myApp := app.New()
    myWindow := myApp.NewWindow("Gopher")


Enter fullscreen mode Exit fullscreen mode

要使图形应用程序正常工作,我们首先需要创建一个新的应用程序和一个窗口。因此,我们创建一个包含单个窗口的新应用程序,其标题为“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)


Enter fullscreen mode Exit fullscreen mode

主菜单包含文件帮助菜单:



├── File
│   └── Quit
└── Help
    └── About


Enter fullscreen mode Exit fullscreen mode

当我们点击“文件”>“退出”时,应用程序将退出。
当我们点击“帮助”>“关于”时,将显示一个带有“关于”文本的对话框。

在窗口内,我们放置一个文本“显示一个随机的 Gopher!”并将其居中。



    // Define a welcome text centered
    text := canvas.NewText("Display a random Gopher!", color.White)
    text.Alignment = fyne.TextAlignCenter


Enter fullscreen mode Exit fullscreen mode

现在是时候定义我们可爱的 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


Enter fullscreen mode Exit fullscreen mode

为此,我们从 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


Enter fullscreen mode Exit fullscreen mode

得益于新的图像资源和刷新方法,屏幕将更新给最终用户。

之后,我们用三个元素定义一个垂直框并将其设置到我们的窗口中:



    // Display a vertical box containing text, image and button
    box := container.NewVBox(
        text,
        gopherImg,
        randomBtn,
    )

    // Display our content
    myWindow.SetContent(box)


Enter fullscreen mode Exit fullscreen mode

垂直框布局将项目按列排列。每个项目的高度设置为最小值,所有项目的宽度均相等,设置为最小宽度中的最大值。

我们监听用户按下键盘上的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()


Enter fullscreen mode Exit fullscreen mode

该方法是和 的Window.ShowAndRun()快捷方式Window.Show()App.Run()

调用myApp.Run()或之后myWindow.ShowAndRun(),我们的应用程序将运行,并且函数将在窗口关闭后返回。

测试一下!

现在是时候测试我们的第一个图形应用程序了,为此我们将运行它:



$ go run main.go


Enter fullscreen mode Exit fullscreen mode

随机地鼠

太棒了,我们的桌面应用程序正在运行!

我们可以点击“随机”按钮,另一只可爱的地鼠就会出现:-)。

我们可以点击“帮助”>“关于”菜单来显示我们的关于信息:

应用程序菜单

帮助 关于

我们也可以按下键盘上的Esc键,应用程序就会退出 ;-)。

太好了,我们的小桌面应用程序运行正常!

作为移动设备进行测试

您是否知道我们还可以在移动环境中测试应用程序并进行模拟?

使用以下命令,我们将看到我们的应用程序如何在移动设备上运行:



$ go run -tags mobile main.go


Enter fullscreen mode Exit fullscreen mode

或者通过我们的任务:



$ task run-mobile
task: [run-mobile] GOFLAGS=-mod=mod go run -tags mobile main.go


Enter fullscreen mode Exit fullscreen mode

在移动设备上测试

帮助>关于移动模拟菜单

如您所见,菜单的显示与 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


Enter fullscreen mode Exit fullscreen mode

有了这些,我们可以轻松地构建应用程序。在执行任务之前,让我们先解释一下 GUI 和移动应用程序的打包。

为多个操作系统打包可能是一项复杂的任务。图形应用程序通常具有与其关联的图标和元数据,以及与每个环境集成所需的特定格式。

fyne命令支持准备在工具包支持的所有平台上分发的应用程序。运行该fyne package命令将创建一个应用程序,该应用程序可安装在一台计算机上,并且只需从当前目录复制创建的文件即可分发到其他计算机。

让我们构建/打包它:



$ task package
task: [package] fyne package -icon gopher.png


Enter fullscreen mode Exit fullscreen mode

此命令会为当前操作系统创建一个嵌入图标的应用程序。
我使用的是 MacOS,因此以下命令会为其生成一个应用程序:
应用程序

双击它时,桌面应用程序将启动,并带有我们可爱的图标:

酒吧中的应用程序

task package如果您在 Windows 环境中运行命令,您将获得一个.exe可执行文件。
在 MacOS 计算机上,您将获得一个.app软件包(如本文所示)。
对于 Linux,您将获得一个.tar.xz可以按常规方式安装的文件(或者在解压的文件夹中运行 make install)。

您还可以指定目标操作系统,如下所示:



$ fyne package -os windows -icon myapp.png


Enter fullscreen mode Exit fullscreen mode

...并将其打包为 Android 和 iOS!

交叉编译

要在真实的移动设备上运行,需要打包应用程序。为此,我们可以使用该fyne package命令。

让我们为 Android 打包我们的应用程序:



$ fyne package -os android -appID com.scraly.gopher -icon gopher.png


Enter fullscreen mode Exit fullscreen mode

或者执行我们的任务:



$ task package-android
task: [package-android] fyne package -os android -appID com.scraly.gopher -icon gopher.png


Enter fullscreen mode Exit fullscreen mode

我们也可以对 iOS 做同样的事情:



$ task package-ios
task: [package-ios] fyne package -os ios -appID com.scraly.gopher -icon gopher.png


Enter fullscreen mode Exit fullscreen mode

/!\ 警告:为了打包 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


Enter fullscreen mode Exit fullscreen mode

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


Enter fullscreen mode Exit fullscreen mode

發佈它!

星际之门

我们运行它、测试它、构建它、打包它,那么现在最后一步是什么呢?我们可以分发我们的应用程序!

众所周知,在 Play 和 App Store 上分发我们的应用非常麻烦。正因如此,我们fyne release才有了命令。

只需一个命令,您就可以将您的应用捆绑到 Play 商店:



$ fyne release -os android -appID com.example.myapp -appVersion 1.0 -appBuild 1


Enter fullscreen mode Exit fullscreen mode

如果您有兴趣分发您的应用程序,请遵循完整的说明

结论

正如我们在本文中看到的,使用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
PREV
理解 Docker:第 10 部分 - 清理和清除
NEXT
通过示例学习 Go:第 3 部分 - 使用 Go 创建 CLI 应用程序