Fyne ( go跨平台GUI )中文文档- 数据绑定 (六)

本文档注意参考官网(developer.fyne.io/) 编写, 只保留基本用法

go代码展示为Go 1.16 及更高版本, idegoland2021.2

这是一个系列文章:

Fyne ( go跨平台GUI )中文文档-入门(一)-CSDN博客

Fyne ( go跨平台GUI )中文文档-Fyne总览(二)-CSDN博客

Fyne ( go跨平台GUI )中文文档-绘图和动画(三)-CSDN博客

Fyne ( go跨平台GUI )中文文档-容器和布局 (四)-CSDN博客

Fyne ( go跨平台GUI )中文文档-小部件 (五)-CSDN博客

Fyne ( go跨平台GUI )中文文档- 数据绑定 (六)-CSDN博客

Fyne ( go跨平台GUI )中文文档- 扩展Fyne (七)-CSDN博客

Fyne ( go跨平台GUI )中文文档- 架构 (八)完结-CSDN博客

6. 数据绑定

6.1 介绍

数据绑定是版本v2.0.0中引入的Fyne工具包的一个强大的新增功能。通过使用数据绑定,我们可以避免手动管理许多标准对象,如LabelButtonList

绑定支持许多原始类型(如Int,String等Float)、列表(如StringList, BoolList)以及MapStruct绑定。这些类型中的每一种都可以使用简单的构造函数来创建。例如,要创建一个具有零值的新字符串绑定,您可以使用binding.NewString(). 您可以使用GetSet方法获取或设置数据绑定的值。

也可以使用名称开头的类似函数绑定到现有值,Bind并且它们都接受指向类型绑定的指针。要绑定到现有的int,我们可以使用binding.BindInt(&myInt). 通过保留对绑定值而不是原始变量的引用,我们可以配置小部件和函数以自动响应任何更改。如果直接更改外部数据,一定要调用Reload()确保绑定系统读取到新值。

Go 复制代码
package main

import (
    "log"

    "fyne.io/fyne/v2/data/binding"
)

func main() {
    boundString := binding.NewString()
    s, _ := boundString.Get()
    log.Printf("Bound = '%s'", s)

    myInt := 5
    boundInt := binding.BindInt(&myInt)
    i, _ := boundInt.Get()
    log.Printf("Source = %d, bound = %d", myInt, i)
}
6.2 绑定简单的小部件

绑定小部件的最简单形式是将绑定项作为值而不是静态值传递给它。许多小部件提供了一个WithData构造函数,该构造函数将接受一个类型化的数据绑定项。要设置绑定,您需要做的就是传入正确的类型。

尽管这在初始代码中可能看起来没有多大好处,但您可以看到它如何确保显示的内容始终与数据源保持同步。您会注意到我们不需要在Label部件调用Refresh() ,甚至不需要保留对它的引用,但它会适当地更新。

Go 复制代码
package main

import (
    "time"

    "fyne.io/fyne/v2/app"
    "fyne.io/fyne/v2/data/binding"
    "fyne.io/fyne/v2/widget"
)

func main() {
    myApp := app.New()
    w := myApp.NewWindow("Simple")

    str := binding.NewString()
    str.Set("Initial value")

    text := widget.NewLabelWithData(str)
    w.SetContent(text)

    go func() {
        time.Sleep(time.Second * 2)
        str.Set("A new string")
    }()

    w.ShowAndRun()
}
6.3 双向绑定

值得庆幸的是,Fyne 中提供的绑定是"双向的",这意味着可以将值推入其中并读出。数据的变化将传达给所有连接的代码,无需任何额外的代码。

要查看实际情况,我们可以更新最后一个测试应用程序以显示绑定到相同值的LabelEntry通过设置,您可以看到通过条目编辑值也会更新标签中的文本,无需在我们的代码中调用刷新或引用小部件。

通过移动您的应用程序以使用数据绑定,您可以停止保存指向所有小部件的指针。通过将您的数据捕获为一组绑定值,您的用户界面可以是完全独立的代码。阅读更清晰,更易于管理。

Go 复制代码
package main

import (
    "fyne.io/fyne/v2/app"
    "fyne.io/fyne/v2/container"
    "fyne.io/fyne/v2/data/binding"
    "fyne.io/fyne/v2/widget"
)

func main() {
    myApp := app.New()
    w := myApp.NewWindow("Two Way")

    str := binding.NewString()
    str.Set("Hi!")

    w.SetContent(container.NewVBox(
        widget.NewLabelWithData(str),
        widget.NewEntryWithData(str),
    ))

    w.ShowAndRun()
}
6.4 数据转换

到目前为止,我们已经使用了数据类型与输出类型匹配的数据绑定(例如Stringand Labelor Entry)。通常需要呈现并不是正确类型的数据, 为此,该binding软件包提供了许多有用的类型转换功能。

最常见的是,这将用于将不同类型的数据转换为字符串以显示在小部件LabelEntry。在代码中查看我们如何通过binding.FloatToStringFloat转换为String 。可以通过移动滑块来编辑原始值。每次数据更改时,它都会运行转换代码并更新连接的小部件。

也可以使用格式字符串为用户界面添加更自然的输出。您可以看到我们的short绑定也将 Float转换为string,但通过使用WithFormat帮助器,我们可以传递格式字符串(类似于fmt包)以提供自定义输出。

Go 复制代码
package main

import (
    "fyne.io/fyne/v2/app"
    "fyne.io/fyne/v2/container"
    "fyne.io/fyne/v2/data/binding"
    "fyne.io/fyne/v2/widget"
)

func main() {
    myApp := app.New()
    w := myApp.NewWindow("Conversion")

    f := binding.NewFloat()
    str := binding.FloatToString(f)
    short := binding.FloatToStringWithFormat(f, "%0.0f%%")
    f.Set(25.0)

    w.SetContent(container.NewVBox(
        widget.NewSliderWithData(0, 100.0, f),
        widget.NewLabelWithData(str),
        widget.NewLabelWithData(short),
    ))

    w.ShowAndRun()
}
6.5 List数据

首先我们创建一个StringList数据绑定,它是一个String数据类型列表。一旦我们有了列表类型的数据,我们就可以将其连接到标准List小部件。为此,我们使用 widget.NewListWithData构造函数,就像其他小部件一样。

将此代码与[列表浏览]进行比较 您将看到 2个主要变化,第一个是我们将数据类型作为第一个参数而不是长度回调函数传递。第二个变化是最后一个参数,我们的UpdateItem回调。修订后的版本采用一个binding.DataItem值而不是widget.ListIndexID. 当使用这个回调结构时,我们应该Bind对模板标签小部件而不是调用SetText. 这意味着如果数据源中的任何字符串发生更改,表中每个受影响的行都将刷新。

Go 复制代码
package main

import (
    "fmt"

    "fyne.io/fyne/v2"
    "fyne.io/fyne/v2/app"
    "fyne.io/fyne/v2/container"
    "fyne.io/fyne/v2/data/binding"
    "fyne.io/fyne/v2/widget"
)

func main() {
    myApp := app.New()
    myWindow := myApp.NewWindow("List Data")

    data := binding.BindStringList(
        &[]string{"Item 1", "Item 2", "Item 3"},
    )

    list := widget.NewListWithData(data,
        func() fyne.CanvasObject {
            return widget.NewLabel("template")
        },
        func(i binding.DataItem, o fyne.CanvasObject) {
            o.(*widget.Label).Bind(i.(binding.String))
        })

    add := widget.NewButton("Append", func() {
        val := fmt.Sprintf("Append new Item %d", data.Length()+1)
        data.Append(val)
    })
    myWindow.SetContent(container.NewBorder(nil, add, nil, nil, list))
    myWindow.ShowAndRun()
}

在我们的演示代码中,有一个 "Append"的按钮,当点击它时,它将向数据源附加一个新值。这样做将自动触发数据更改处理程序并展开List小部件以显示新数据。

相关推荐
意倾城36 分钟前
Spring Boot 配置文件敏感信息加密:Jasypt 实战
java·spring boot·后端
火皇40536 分钟前
Spring Boot 使用 OSHI 实现系统运行状态监控接口
java·spring boot·后端
rylshe13141 小时前
在scala中sparkSQL连接mysql并添加新数据
开发语言·mysql·scala
小宋加油啊1 小时前
Mac QT水平布局和垂直布局
开发语言·qt·macos
薯条不要番茄酱1 小时前
【SpringBoot】从零开始全面解析Spring MVC (一)
java·spring boot·后端
MyhEhud1 小时前
kotlin @JvmStatic注解的作用和使用场景
开发语言·python·kotlin
想睡hhh1 小时前
c++进阶——哈希表的实现
开发语言·数据结构·c++·散列表·哈希
Clown952 小时前
Go语言爬虫系列教程(一) 爬虫基础入门
开发语言·爬虫·golang
Watermelo6172 小时前
前端如何应对精确数字运算?用BigNumber.js解决JavaScript原生Number类型在处理大数或高精度计算时的局限性
开发语言·前端·javascript·vue.js·前端框架·vue·es6
Aric_Jones4 小时前
lua入门语法,包含安装,注释,变量,循环等
java·开发语言·git·elasticsearch·junit·lua