Skip to content

控件引用 (Control Refs) ​


Flet 控件是对象,为了访问它们的属性,我们需要保留对这些对象的引用(变量)。

考虑以下示例:

python
import flet as ft

def main(page):
    first_name = ft.TextField(label="First name", autofocus=True)
    last_name = ft.TextField(label="Last name")
    greetings = ft.Column()

    async def btn_click(e):
        greetings.controls.append(ft.Text(f"Hello, {first_name.value} {last_name.value}!"))
        first_name.value = ""
        last_name.value = ""
        page.update()
        await first_name.focus()

    page.add(
        first_name,
        last_name,
        ft.Button("Say hello!", on_click=btn_click),
        greetings,
    )

ft.run(main)

在 main() 方法的最开始,我们创建了三个将在按钮的 on_click 回调中使用的控件:两个用于输入姓和名的 TextField,以及一个用于显示问候信息的 Column 容器。我们创建控件并设置好它们的所有属性,在 main() 方法的末尾调用 page.add() 时,我们传入了这几个控件的引用(变量)。

然而,当添加越来越多的控件和事件处理程序时,在同一个地方保留所有控件定义会变得非常困难,它们会分散在整个 main() 函数的主体中。此时再粗略看一下 page.add() 里的参数,如果不频繁跳转到 IDE 中的变量定义去,很难直观想象出最终的界面长什么样:

python
    page.add(
        first_name,
        last_name,
        ft.Button("Say hello!", on_click=btn_click),
        greetings,
    )

first_name 是一个 TextField 吗?它设置了自动聚焦(autofocus)吗?greetings 是一个 Row 还是一个 Column?


Ref 类 (Ref class) ​

Flet 提供了 Ref 工具类,它允许你先定义控件的引用,并在事件处理程序中使用该引用,随后在构建控件树时再将引用绑定到真正的具体控件上。这个概念源于 React。

定义一个新的带类型的控件引用:

python
first_name = ft.Ref[ft.TextField]()

要访问被引用的具体控件(解引用),使用 Ref.current 属性:

python
# 清空 first_name 输入框的值
first_name.current.value = ""

要将控件绑定到引用,请将控件的 ref 属性设置为该引用:

python
page.add(
    ft.TextField(ref=first_name, label="First name", autofocus=True)
)

注意

所有 Flet 控件都支持 ref 属性。


我们可以使用引用来重写我们最开始的那个程序:

python
import flet as ft

def main(page):

    first_name = ft.Ref[ft.TextField]()
    last_name = ft.Ref[ft.TextField]()
    greetings = ft.Ref[ft.Column]()

    async def btn_click(e):
        greetings.current.controls.append(
            ft.Text(f"Hello, {first_name.current.value} {last_name.current.value}!")
        )
        first_name.current.value = ""
        last_name.current.value = ""
        page.update()
        await first_name.current.focus()

    page.add(
        ft.TextField(ref=first_name, label="First name", autofocus=True),
        ft.TextField(ref=last_name, label="Last name"),
        ft.Button("Say hello!", on_click=btn_click),
        ft.Column(ref=greetings),
    )

ft.run(main)

现在,我们能够非常清晰地在 page.add() 调用中一目了然地看出整个页面的层级结构以及构成它的所有控件。

是的,由于需要使用 .current. 来访问被引用的具体控件,编写代码逻辑时稍微多了一些字符,但这完全取决于你个人的偏好 😃


关注我,学习大模型、大数据、Python等热门技术。