用户控制

用户控件 ( UserControl) 允许通过组合现有的 Flet 控件来构建隔离的可重用组件。用户控件的行为类似于Control,可以具有方法和属性。

下面是用户控制的最小示例:

class GreeterControl(UserControl):
    def build(self):
        return Text("Hello!")

def main(page):
    page.add(GreeterControl())

flet.app(target=main)

UserControl 必须实现build()为构建控件的 UI 而调用的方法,并且应该返回单个Control实例或一个List控件。UserControl继承自Stack,因此多个孩子将被安排在彼此之上。如果您需要以不同方式排列控件的 UI Row,请使用Column或其他布局控件,例如:

class GreeterControl(UserControl):
    def build(self):
        return Column([
            TextField(label="Your name"),
            ElevatedButton("Login")
        ])

UserControl 与外部布局隔离,即当update()为父控件调用方法时,UserControl 内部的任何更改都不会包含在更新摘要中。UserControl 应调用self.update()以将其更改推送到 Flet 页面,例如:

class Counter(UserControl):
    def add_click(self, e):
        self.counter += 1
        self.text.value = str(self.counter)
        self.update()

    def build(self):
        self.counter = 0
        self.text = Text(str(self.counter))
        return Row([self.text, ElevatedButton("Add", on_click=self.add_click)])

def main(page):
    page.add(Counter(), Counter())

flet.app(target=main)

您可以将事件处理程序(例如def add_click(self, e))和控件引用(例如self.text)声明为类成员,或者build()使用局部变量和内部函数在方法内部实现所有 UserControl 的逻辑。例如,上面的代码可以重写为:

class Counter(UserControl):
    def build(self):

        self.counter = 0
        text = Text(str(self.counter))

        def add_click(e):
            self.counter += 1
            text.value = str(self.counter)
            self.update()

        return Row([text, ElevatedButton("Add", on_click=add_click)])
class Counter(UserControl):
    def build(self):

        self.counter = 0
        text = Text(str(self.counter))

        def add_click(e):
            self.counter += 1
            text.value = str(self.counter)
            self.update()

        return Row([text, ElevatedButton("Add", on_click=add_click)])

注意 counter不能声明为局部变量,因为它在add_click方法内部不可见,因此必须声明为类字段self.counter

用户控件可以有一个构造函数来传递自定义数据,例如:

class Counter(UserControl):
    def __init__(self, initial_count):
        super().__init__()
        self.counter = initial_count

    def build(self):
        text = Text(str(self.counter))
        def add_click(e):
            self.counter += 1
            text.value = str(self.counter)
            self.update()

        return Row([text, ElevatedButton("Add", on_click=add_click)])

# then use the control
def main(page):
    page.add(
        Counter(100),
        Counter(200))

注意 super().__init__()必须始终在您自己的构造函数中调用。

用户控件提供生命周期“挂钩”方法:

  • did_mount()- 在将 UserControl 添加到页面并分配瞬态之后调用id。
  • will_unmount()- 在从页面中删除 UserControl 之前调用。

使用这些方法,我们可以实现一个简单的“倒计时”控件:

class Countdown(UserControl):
    def __init__(self, seconds):
        super().__init__()
        self.seconds = seconds

    def did_mount(self):
        self.running = True
        self.th = threading.Thread(target=self.update_timer, args=(), daemon=True)
        self.th.start()

    def will_unmount(self):
        self.running = False

    def update_timer(self):
        while self.seconds and self.running:
            mins, secs = divmod(self.seconds, 60)
            self.countdown.value = "{:02d}:{:02d}".format(mins, secs)
            self.update()
            time.sleep(1)
            self.seconds -= 1

    def build(self):
        self.countdown = Text()
        return self.countdown

def main(page):
    page.add(Countdown(120), Countdown(60))

flet.app(target=main)