跨平台GUI框架Fyne API架构_Fyne


宏观上看,整个Fyne工具包分为两个子项目:

  1. “Fyne/v2”(开发人员主要参考此API);
  2. “Fyne/v2/driver”(桌面环境的操作系统特定代码和渲染器)。

一、fyne/v2

Fyne子项目是相应于UI和应用程序开发部分的高级API。该项目定义了开发人员将与之交互的主要API,它定义了窗口、小部件和画布的交互。布局、用户交互和主题等都在这个API中定义。

在一个Fyne程序中,应用程序UI是通过各种Widgets或CanvasObjects定义的。容器用于容纳多个小部件或对象,这些子对象的排列由各种布局组件来控制。需要注意的是,如果开发人员或工具创建者发现创建一棵对象树比操作此类API更容易使用,则他可以通过例如json等格式的静态文件来串行化对象树。

当然,此API的核心是基于纯Go语言实现的,这使得Fyne应用程序的开发与测试都非常迅速并具有高度可移植性。

(一)fyne/v2/canvas

canvas画布包fyne/canvas包含用于管理可以绘制到画布的图形元素的API。此包中的对象通过它们公开的字段进行操作。开发人员可以使用其中函数的构造函数来创建图形对象。

如果在创建图形对象后想再更改此可见对象的属性,则可能应该调用canvas.Refresh(obj)以请求重新绘制它。

(二)fyne/v2/widget

Widgets工具是Fyne GUI的主要部分——在Fyne程序窗口中使用的大多数元素都在这个包中定义。与canvas包一样,您可以使用对象的属性来控制其逻辑状态。与canvas包不同的是,这些元素对API隐藏了图形细节,因此实现细节不会与小部件交互的意图混淆。

对小部件Widgets的调用通常是基于函数而非属性的,当以这种方式使用时,UI将自动更新。如果您更改小部件中的字段,请确保一定要调用canvas.Refresh(widget)(如果您想同时更改小部件中的多个字段,这会更高效)。

(三)fyne/v2/test

这个测试包有助于编写GUI单元测试,甚至支持测试驱动开发。如test.Tap和test.Type(string)等实用程序函数支持模拟用户输入,而不必直接操作测试中的小部件。

二、fyne/v2/driver

这个驱动程序包API部分包含特定于平台的驱动程序扩展。开发过程中,如果非要使用这些API,请确保代码由If语句或类型(type)检查保护——否则可能会导致运行时出现问题。

(一)fyne/v2/driver/desktop

这一组API用于在桌面版本运行的扩展,包括扩展的键盘支持和详细的鼠标处理信息。

(二)fyne/v2/internal

这一组API包含用于实现Fyne工具包的有用代码,这些代码不向普通开发人员公开。有时,在迁移到公开导出的API之前,这些API可能还要在内部包中进行测试。

(1)fyne/v2/internal/driver

此内部包包含负责显示Fyne应用程序以及处理用户输入和系统信息的驱动程序。有两组驱动程序:glfw(通过go-gl和glfw使用OpenGL库)和gomobile(使用GLES和gomoobile项目)(我们将来可能还会考虑加入其他的驱动程序)。驱动程序为各种操作系统和驱动程序组合(例如3D加速)提供了模块支持。

这一组API的代码是一个Go、CGo和C的混合体,这意味着它们的可移植性较差。任何添加的新功能都需要至少支持Fyne目前所支持的所有以下平台:

  • macOS (10.12+)
  • Windows (7+)
  • Linux (X11)
  • Linux on Raspberry Pi (3+)
  • FreeBSD, OpenBSD and NetBSD (X11)
  • iOS (1.7+)
  • Android (4+)

(2)fyne/v2/internal/painter

这个渲染组件painter包中包含实际渲染Fyne画布内容的模块。目前有两种绘制方案:gl(使用OpenGL或GLES绘制)软件版本的gl(直接在内存中处理图形)。其中,gl包是硬件加速的,大多数Fyne驱动程序都使用它——它需要CGo进行编译,但由于其高性能特征,因此普遍认为这么复杂是值得的。软件版本的painter可用于通过其他自动化脚本实现测试和生成图像捕获-它为Go Playground预览版本以及我们文档中的图像部分提供支持。

三、驱动程序进一步分析

Fyne中的驱动程序负责提供API的所有特定于操作系统的实现,以创建完整的应用程序。它也可能依赖于一个Painter来执行绘图操作(请参阅本文档后面的内容)。

目前Fyne中一共提供了3种驱动程序:glfw,gomobile和test

(一)GLFW

主Fyne驱动程序负责使用GLFW库打开窗口并处理用户输入。Go-gl项目的glfw项目的Go绑定支持Windows、Linux、macOS和BSD,因此它为所有标准Fyne桌面应用程序提供了支持

您可以在示例应用程序中看到这一点——默认情况下,调用app.New()将设置GLFW驱动程序。从这一点起,任何类似调用app.CreateWindow()的操作都将调用GL绘制程序代码来绘制应用程序界面。

import "fyne.io/fyne/v2/app"

(二)Gomobile

Gomobile驱动程序嵌入了Gomobile项目,用于构建iOS和Android平台的应用程序。要为移动设备打包应用程序,最简单的方法是使用fyne命令,该命令将构建二进制文件,然后将应用程序打包以部署到设备,格式如下:

fyne package -os ios -appID com.company.myapp .

gomobile驱动程序是为ios或android版本自动加载的,但它包括一个有用的“模拟构建”(simulated build)模式。要在移动模式下加载fyne应用程序而不为移动设备进行编译,您可以使用这种mobile构建标记。请注意,这不是一个完整的设备模拟器,因此不应用于实际测试,但它非常适合在移动外形设备上快速加载应用程序界面。

go run -tags mobile main.go

(三)Test

测试驱动程序对于Fyne代码和应用程序逻辑的单元测试非常有帮助。这个驱动程序从不向屏幕呈现任何内容,而是按预期执行所有其他代码。这个驱动程序可以在不调用应用程序构造函数的情况下使用,如果在_test.go文件中包含以下导入,则可以在内存中模拟应用程序。

import _ "fyne.io/fyne/test"

(四)新一代驱动程序

随着时间的推移,添加新的驱动程序或将现有驱动程序的一部分迁移到新技术可能会变得有用。例如,新的驱动程序将可以使Fyne能够在网络浏览器中运行,或者对现有glfw驱动程序的更新可以增加对新平台的支持或更好的性能。

需要一个新的驱动程序来实现所有的fyne.Driver接口,主要负责管理应用程序中的本机窗口。驱动程序创建的每个窗口都需要包含一个画布,这是驱动程序的核心职责——渲染的链接。

这种新式的驱动程序必须能够呈现画布包中定义的所有类型的画布对象(当前为线条、矩形、文本和图像(位图和SVG))。小部件和GUI是使用这些基本对象绘制的,因此驱动程序不需要编程任何小部件渲染。它需要从每个Window实例遍历对象树,因此必须了解如何使用fyne.Container和fyne.Widget包装子对象。布局不是驱动程序的一部分,所有定位都在Go代码中处理,并推送到准备渲染的对象状态。

驱动程序还必须处理用户输入,通常是鼠标、键盘和触摸屏。它应该创建适当的fyne.KeyEvent和fyne.MouseEvent对象,并将它们发送到设置为处理事件的对象。

四、渲染组件Painter

Fyne框架中提供了三个不同的Painter,分别是gl,gles和software。

(一)GL

这个最基础和最关键部分Fyne驱动程序负责使用OpenGL来渲染用户界面。Go-gl项目的Go绑定实现连接到桌面应用程序上的高效系统渲染器,从而为所有桌面Fyne应用程序提供支持。OpenGL驱动程序使用2008年的2.0版本规范,因此大多数设备都应该支持它,尽管也有一些例外。

像Raspberry Pi这样的嵌入式设备并不能提供完整的OpenGL实现,因此这个渲染组件Painter有一个使用OpenGL ES的变体(见下面)。

(二)GLES

对于低功率嵌入型设备,Fyne中使用GLES规范。这是为Raspberry Pi、iOS和Android版本自动选择的。使用GLES的应用程序看起来与使用完整GL渲染组件Painter的应用程序完全相同,但未来可能不支持某些高级功能。对于同时支持GL和GLES的系统,默认情况下将使用完整的GL实现,您可以使用gles构建标记进行更改。

go run -tags gles main.go


(三)软渲染组件Painter

有一个名为“software”的渲染组件工具,它能够使用基本的绘图程序将用户界面渲染到内存中。此渲染的结果可以使用Canvas.Capture()发现,并返回一个标准的image.Image。注意,这不是一个效率很高的渲染组件,但在测试或其他场景中可能对开发有所帮助

开发过程中,您可以专门创建一个software类型的渲染组件,而无需加载不同类型的应用程序或驱动程序。只需使用以下代码即可避免加载完整的用户界面。

import "fyne.io/fyne/v2/tools/playground"

func main() {
  ...

  canvas := playground.NewSoftwareCanvas()
  // add items to the canvas as normal

  img := canvas.Capture()
  // use the image as you wish
}

(四)新一代Painter

要添加新的渲染器,则必须需要满足上一节中的画布要求——在正确的位置绘制基元类型并处理用户输入。要将这种新式渲染组件包含在现有的驱动程序中,需要构建标记或操作系统特定的文件,并且可能还需要在驱动程序中进行额外的工作。

总结

请记住,借助于上面所有各组的API,我们的开发最终目标是使构建美观的应用程序变得简单且快捷。当然,内部的一些复杂性是实现这一目标所必需的。尽管如此,任何想要加入项目的新开发人员都必须确保Fyne应用程序的核心代码都经过了很好的测试并能够维护和扩展。最后,我们介绍了框架中驱动程序的不同类型与渲染器组件,显然新一代驱动程序与新式渲染器Painter要真正发展与完善起来还需要一个较长的历程。