自上世纪 80 年代以来,我一直徜徉在代码的世界里。近年来,我一直在探索用 Go 语言编写 GUI 程序的各种可能性,尤其希望能找到合适的工具来构建跨平台桌面 GUI 软件。当然,如果能用同一套技术开发移动版本,那就更令人兴奋了,毕竟,节省开发人员宝贵时间和精力的技术,谁不爱呢?
然而,一番探索下来,我却发现了一个残酷的事实:Go 语言目前还没有一个真正好用的 GUI 框架! 这实在令人惋惜,因为除了 GUI 这一点,Go 语言几乎完美契合了我对易用、快速的应用程序开发工具的所有想象,就像我曾经钟爱的 REALBasic(现在更名为价格不菲的 Xojo) 那样。遗憾的是,到目前为止,还没有任何一个框架或语言+IDE+框架的组合能够超越 REALBasic 带给我的高效开发体验。
我并非没有尝试过其他的选择。 Lazarus 和 Object Pascal 也曾进入我的视野,但 Object Pascal 毕竟年岁已高,语言本身的局限性难以忽视,而且有时还需要手动管理内存,这对于桌面 GUI 应用程序来说简直是噩梦。我也曾考虑过其他我比较熟悉且喜欢的语言。
Racket 拥有非常完善的 GUI 工具包,我曾经用它编写和维护过多年的 GUI 应用程序。然而,用 Racket 开发的 GUI 应用程序反应迟钝,启动时间也令人捉急,这使得它在开发 「轻快敏捷」 的小型 GUI 应用程序时显得力不从心。
Ada 给我的感觉就像是在不断积累技术债务,而且缺乏第三方库的支持。它唯一还算过得去的 GUI 选项是 GTK3 。我还尝试过 CommonLisp,但它总是给我一种 「拼拼凑凑」 的感觉,而且现有的第三方库缺乏文档,可靠性也值得怀疑。至于 Rust,我已经学习了它的语法,甚至从头到尾啃完了 Klabnik 和 Nichols 合著的那本 「巨著」,但我不得不承认,Rust 给我的感觉是过度设计,并不吸引我。它是否真的适合开发高完整性系统,我持保留意见 (我仍然推荐 Ada/Spark 来完成这类任务) 。此外,Rust 在 GUI 编程方面没有任何优势,而且它的社区氛围也让人不敢恭维。
所以,在一番权衡之后,我还是选择了 Go 语言来开发一个大型项目,而 GUI 库的选择也提上了日程。以下是我对 Go 语言 GUI 框架的个人看法,仅供参考。
🎭 各显神通:Go 语言 GUI 框架大比拼
在 Go 语言的世界里,GUI 框架虽然数量不多,但也称得上是 「百花齐放」 。下面,我将逐一介绍这些框架的特点、优缺点以及适用场景,希望能帮助读者朋友们找到适合自己的那一款。
1️⃣ Fyne:叫好不叫座?
- 官方网站: https://fyne.io/
- 测试情况: 经过广泛测试
- 评分: 5/10
- 更新/修复频率: 频繁且迅速
- 推荐指数: 仅推荐用于移动应用程序开发
Fyne 基本上是一个人带着一群合作者的成果。我的感受是,Fyne 的开发者们更擅长推广他们的框架,而不是编写 GUI 框架。 Fyne 在设计上存在一些根本性的缺陷。其中最大的问题是,他们试图用完全相同的代码来开发桌面和移动应用程序。要知道,手机和平板电脑的尺寸和交互方式与桌面电脑截然不同,这种 「一刀切」 的想法显然行不通。桌面应用程序与移动应用程序有着本质的区别,这是 Fyne 开发者们需要正视的问题。
由于 Fyne 的设计理念存在偏差,他们做出了一系列令人费解的选择。例如,他们将布局与控件分离,这使得一切都变得异常复杂,使用起来一点也不简单。 Fyne 提供的布局机制倾向于将其内容最小化,控件只存储最小尺寸 (所有控件的默认值),而没有首选尺寸或最大尺寸。此外,Fyne 的控件没有锁定顶部、左侧、底部、右侧或其他合理的机制来控制它们在嵌入窗口或面板大小调整时的行为。 Fyne 还没有 Z-order 机制来控制控件之间的切换顺序。
另一个大问题是,Fyne 缺乏合理的文件路径抽象。开发者们坚持认为所有东西都应该是 URL,显然没有意识到 URL 标准并没有以跨平台的方式指定包含卷信息的绝对路径。虽然 URI 方案有一些扩展可以使用盘符,Fyne 也使用了一些他们认为合适的方案,但这些基于/
或\
的本地文件系统路径转换存在很多问题。例如,如何处理可移动驱动器?如何处理 Windows 上的盘符?如何构造路径、遍历文件系统?到目前为止,Fyne 并没有提供任何帮助,甚至坚持认为每个 URI 都代表一个任意的资源,你不应该假设它指向一个文件,它也可能是一个网络资源。难道网络访问和文件访问真的可以一概而论吗?
总而言之,Fyne 并不适合开发桌面应用程序,尽管它在移动平台上可能还不错。用 Fyne 很难设计出复杂的桌面应用程序界面。默认情况下,Fyne 应用程序会违反所有平台上的人机界面指南,而开发者们似乎对此感到非常自豪。你将不得不花费数天甚至数周的时间来为一些简单的事情创建自己的专用布局算法,而这些事情在其他合理的、标准的布局系统中只需几分钟或几小时就能完成。
2️⃣ Gio:未来可期
- 官方网站: https://gioui.org/
- 测试情况: 未经测试
- 评分: 6/10
- 更新/修复频率: 一般,速度较慢
- 推荐指数: 很有潜力,但我还没有对其进行详细测试
Gio 是一个非常有前途的立即模式 GUI 框架,它也包含一些状态 ful 控件。一些人认为它是 Fyne 的良好替代品,它拥有你在应用程序中期望的大多数控件。在我看来,Gio 的使用方法似乎有些复杂和繁琐——如果你查看示例代码,就会发现即使是简单的入门程序也需要编写大量的样板代码。然而,Gio 最大的缺点是缺乏文档,这使得它很难上手,你在一开始可能会迷失方向。尽管如此,我仍然计划在将来找个时间试用一下 Gio,至少将其作为 GIU 的替代方案进行测试。我还没有测试过它对编辑器控件的支持程度——框架是否能够支持复杂的文本编辑 (多行文本、富文本甚至嵌入图像) 是衡量 GUI 框架优劣的试金石之一,因为多行文本编辑是目前为止最难正确实现的功能。我还没有仔细研究过 Gio 的代码,但我猜测它在这方面的表现应该与 Giu 类似。
3️⃣ Giu:小项目利器
- 官方网站: https://github.com/AllenDang/giu
- 测试情况: 经过广泛测试
- 评分: 6/10
- 更新/修复频率: 一般,速度较慢
- 推荐指数: 推荐用于小型项目,但在投入使用前请仔细检查其局限性
Giu 是一个不太为人知的立即模式 GUI 框架,它基于 imgui 的 Go 语言分支,使用了 imgui 的 C 语言库。 Giu 非常易于使用,在我测试过的所有 GUI 框架中,它可能是让我最快获得满意结果的框架,尽管它的速度比不上 Lazarus 这样的传统 RAD 工具。 Giu 拥有你可能需要的大多数控件,但有两个明显的缺陷:
- 缺少文件对话框: Giu 没有提供文件和文件夹选择/保存对话框,以及其他一些常见的简单对话框。我已经设法实现了一些替代方案,足以满足我的使用场景,但你应该意识到,没有原生的文件对话框是一个严重的限制,可能会带来其他问题 (例如,缺乏与 「记住上次文件访问」 功能、拖放功能等的集成) 。
- 多行文本框不支持自动换行: 我已经找到了解决这个问题的方法,但还没有在 Github 上公开代码。
因此,你应该意识到这可能是一个相当大的限制。然而,与 Fyne 不同的是,Giu 的所有默认设置都很合理,而且用它很容易就能创建出简单到中等复杂度的 GUI,例如包含列表、一些编辑字段、按钮、组合框或单选按钮、菜单以及一两个窗口拆分器的界面。 Giu 的外观和感觉一点也不原生,但总体来说还不错。你可以访问底层的 imgui 库,但要注意,imgui 本身非常简陋,Go 语言版本没有像 C 语言版本那样提供高级的状态 ful 控件。
4️⃣ GTK:老牌劲旅
- 官方网站:
- GTK3: https://github.com/gotk3/gotk3
- GTK4: https://github.com/diamondburned/gotk4
- 测试情况: 测试过 GTK3
- 评分: 7/10
- 更新频率: 自动生成
- 推荐指数: GTK4 可能是目前开发大型复杂桌面应用程序的最佳选择,这类应用程序通常使用 Qt 来开发
5️⃣ IUP:简单易用
- 官方网站: https://github.com/matwachich/iup
- 测试情况: 未经测试
- 评分: 5/10
- 更新频率: 从未更新
- 推荐指数: IUP 在 Linux 和 Windows 平台上口碑不错,它可能是一个比 GTK 更容易部署的替代方案,值得一试
6️⃣ Qt:受 licensing 限制
- 官方网站: https://github.com/therecipe/qt
- 测试情况: 未经测试
- 评分: 对于没有商业许可的专有软件来说,Qt 的得分为 4/10,但对于 GPL 软件来说,它可能是一个不错的选择
- 更新/修复频率: 很少更新,速度较慢
- 推荐指数: 由于许可证问题,Qt 只适合开发 GPL 软件
7️⃣ Unison:值得关注
- 官方网站: https://github.com/richardwilkes/unison
- 测试情况: 未经测试
- 评分: 无法评分 (演示程序在编译 skia 时出错,因此无法提供截图)
- 更新/修复频率: 正在开发中
我最近才发现 Unison,目前还无法对其做出评价。 Unison 看起来是一个不错的非原生 GUI 框架,它提供了许多标准控件,并且正在为作者的个人项目进行开发。 Unison 的代码看起来非常清晰易懂,所以我建议你尝试一下。我以后也会对它进行更广泛的测试。当然,Unison 目前还不能用于生产环境,尤其是大型 GUI 项目。
8️⃣ Wails:Web 开发者的福音
- 官方网站: https://wails.app/
- 测试情况: 未经测试
- 评分: 7/10
- 更新/修复频率: 频繁且迅速
- 推荐指数: 如果你本来就擅长 Web 开发,那么我强烈推荐你尝试一下 Wails
Wails 是这份清单中唯一的基于 Web 的 GUI 框架,因为它不是我的首要选择。 Wails 允许你使用 Go 语言编写后端代码,并使用任何你喜欢的 Web 框架来开发 GUI 。 Wails 会自动将 Go 代码与 HTML 中的 Javascript 代码链接起来,并渲染 HTML/JS 代码。最终的产物是一个功能齐全的桌面应用程序。我在很多地方都看到过人们推荐 Wails,并将其与各种前端库结合使用。
如果你本来就擅长开发 Web 应用程序,那么我强烈推荐你尝试一下 Wails 。我的目标是使用一个允许我完全使用 Go 语言开发所有组件的 GUI 库,因此 Wails 不在我的考虑范围之内。然而,基于 Web 的界面可以做得非常漂亮,而且熟悉 Web 设计的开发者可能会发现 Wails 比任何非原生的、纯 Go 语言的 GUI 库 (通常基于 Open GL 后端渲染引擎) 都要好用。如果你希望你的应用程序看起来像一个网页 (或者希望保留将其变成真正的 Web 应用程序的选项),那么 Wails 可能是最容易实现这一目标的选择。
🏆 总结:路漫漫其修远兮
总的来说,Go 语言的 GUI 框架选择还是比较有限的。我选择 Giu 来开发一个项目,但其实选择 Gio 也无妨。但我必须承认,我并不喜欢立即模式 GUI 。如果你的 GUI 比较复杂,你最终将不得不编写额外的 「布局缓冲区」 粘合代码来维护状态。例如,我需要从 sqlite 数据库中获取和设置数据,但 Giu 的文本字段只支持字符串,所以我必须单独维护字符串,并在适当的时候从数据库中获取/更新数据。也许 GTK4 是更好的选择,我最终可能会改用 GTK4 。我将来也可能会再给 Fyne 一次机会,但我不抱太大希望。 Fyne 的设计理念过于固执,而且方向也不对。我还考虑过在正式项目中尝试 Wails 。对我来说,学习 Wails 的成本会很高,因为我的 Web 设计知识还停留在上世纪 90 年代末。然而,Wails 在灵活性和重新设计方面的优势可能值得我为之付出努力。
📚 参考文献
- Fyne: https://fyne.io/
- Gio: https://gioui.org/
- Giu: https://github.com/AllenDang/giu
- GTK:
- GTK3: https://github.com/gotk3/gotk3
- GTK4: https://github.com/diamondburned/gotk4
- IUP: https://github.com/matwachich/iup
- Qt: https://github.com/therecipe/qt
- Unison: https://github.com/richardwilkes/unison
- Wails: https://wails.app/
原文链接: https://medium.com/@balle.johannes/no-good-go-gui-9f54813e9bf