主题
控件引用 (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. 来访问被引用的具体控件,编写代码逻辑时稍微多了一些字符,但这完全取决于你个人的偏好 😃