Skip to content

使用Python创建Flet应用程序


入门


使用Python创建Flet应用程序

要编写 Flet 应用程序,您不需要是前端大师,但建议您具备 Python 和面向对象编程的基础知识。

在本文档中,我们将学习一个Flet应用程序的结构,了解如何使用 Flet 控件输出数据、向用户请求数据以及构建基本页面布局。我们还将介绍一些打包和部署选项,以便为您的用户提供现成的应用程序。

安装flet模块

Flet 需要 Python 3.7 或更高版本。要启动 Flet,您需要先安装flet模块:

sh
pip install flet

💥 注意
需要升级flet模块,请运行:
pip install flet --upgrade

要安装 Flet 预发行版(对于高级用户),请运行(初学者不推荐,请忽略):

python
pip install flet --pre

💥 警告
我们建议将预发布版本安装到虚拟环境中。

Linux

在 Linux 和 WSL 上运行 Flet 应用程序需要安装GStreamer库。您的系统中很可能已经安装了它们,但如果您在运行 Flet 应用程序时遇到该错误error while loading shared libraries: libgstapp-1.0.so.0: cannot open shared object file: No such file or directory,则需要安装 GStreamer。

要在 Ubuntu/Debian 上安装 GStreamer,请运行以下命令:

sh
sudo apt-get update
sudo apt-get install libgstreamer1.0-dev libgstreamer-plugins-base1.0-dev libgstreamer-plugins-bad1.0-dev gstreamer1.0-plugins-base gstreamer1.0-plugins-good gstreamer1.0-plugins-bad gstreamer1.0-plugins-ugly gstreamer1.0-libav gstreamer1.0-doc gstreamer1.0-tools gstreamer1.0-x gstreamer1.0-alsa gstreamer1.0-gl gstreamer1.0-gtk3 gstreamer1.0-qt5 gstreamer1.0-pulseaudio

有关在其他 Linux 发行版上安装的信息,请参阅本指南

WSL

Flet 应用程序可以在 WSL2 上运行。如果您遇到cannot open display错误,请按照本指南进行故障排除。

基础应用程序结构

一个非常简单的 Flet 应用程序具有以下结构:

python
import flet as ft

def main(page: ft.Page):
    # 在页面上增加或者更新控件
    pass

ft.app(target=main)

Flet结构

💥 注意
本节特意称为“基础”,因为在本指南的后面部分,我们将学习具有可重用控件的应用程序结构的更真实的方法。

典型的 Flet 程序以调用flet.app()应用程序开始等待新用户会话的位置结束。函数main()是 Flet 应用程序中的入口点。每个用户会话都会在一个新线程上调用它,并Page传递一个实例。在浏览器中运行 Flet 应用程序时,将为每个打开的选项卡或页面启动新的用户会话。作为桌面应用程序运行时,仅创建一个会话。

Page就像特定于用户的“画布”,用户会话的视觉状态。要构建应用程序 UI,您需要向页面添加和删除控件,并更新它们的属性。上面的代码示例将仅向每个用户显示一个空白页面。

默认情况下,Flet 应用程序在本机操作系统窗口中启动,这对于开发来说非常方便。但是,您可以通过修改调用在新的浏览器窗口中打开它,flet.app如下所示:

python
ft.app(target=main, view=ft.AppView.WEB_BROWSER)

信息 在内部,每个 Flet 应用程序都是一个 Web 应用程序,即使在本机操作系统窗口中打开,内置的 Web 服务器仍然会在后台启动。Flet Web 服务器称为“Fletd”,默认情况下它侦听随机 TCP 端口。您可以指定自定义 TCP 端口,然后在浏览器中打开应用程序以及桌面视图:

python
flet.app(port=8550, target=main)

在浏览器中打开http://localhost:<port>以查看 Flet 应用程序的 Web 版本。

用户界面由控件(也称为小部件)组成。要使控件对用户可见,必须将它们添加到Page其他控件中或内部。页面是最顶层的控件。相互嵌套的控件可以表示为以 Page 为根的树。

控件只是常规的 Python 类。通过构造函数创建控件实例,参数与其属性相匹配,例如:

python
t = ft.Text(value="Hello, world!", color="green")

要在页面上显示控件,请将其添加到controls页面列表并调用page.update()以将页面更改发送到浏览器或桌面客户端:

python
import flet as ft

def main(page: ft.Page):
    t = ft.Text(value="Hello, world!", color="green")
    page.controls.append(t)
    page.update()

ft.app(target=main)

笔记 在下面的示例中,我们将仅显示函数的内容main。

您可以修改控件属性,UI 将在下一次更新page.update():

python
t = ft.Text()
page.add(t) # it's a shortcut for page.controls.append(t) and then page.update()

for i in range(10):
    t.value = f"Step {i}"
    page.update()
    time.sleep(1)

有些控件是“容器”控件(如页面),可以包含其他控件。例如,Rowcontrol 允许将其他控件一一排列在一行中:

python
page.add(
    ft.Row(controls=[
        ft.Text("A"),
        ft.Text("B"),
        ft.Text("C")
    ])
)

或TextField旁边ElevatedButton:

python
page.add(
    ft.Row(controls=[
        ft.TextField(label="Your name"),
        ft.ElevatedButton(text="Say my name!")
    ])
)

page.update()足够聪明,只发送自上次调用以来所做的更改,因此您可以向页面添加几个新控件,删除其中一些控件,更改其他控件的属性,然后调用以进行批量更新,例如page.update():

python
for i in range(10):
    page.controls.append(ft.Text(f"Line {i}"))
    if i > 4:
        page.controls.pop(0)
    page.update()
    time.sleep(0.3)

某些控件(例如按钮)可以具有对用户输入做出反应的事件处理程序,例如ElevatedButton.on_click:

python
def button_clicked(e):
    page.add(ft.Text("Clicked!"))

page.add(ft.ElevatedButton(text="Click me", on_click=button_clicked))

以及简单待办事项的更高级示例:

python
import flet as ft

def main(page):
    def add_clicked(e):
        page.add(ft.Checkbox(label=new_task.value))
        new_task.value = ""
        new_task.focus()
        new_task.update()

    new_task = ft.TextField(hint_text="Whats needs to be done?", width=300)
    page.add(ft.Row([new_task, ft.ElevatedButton("Add", on_click=add_clicked)]))

ft.app(target=main)

信息 Flet 实现命令式UI 模型,您可以在其中“手动”构建具有状态控件的应用程序 UI,然后通过更新控件属性来更改它。Flutter 实现了声明式模型,其中 UI 会根据应用程序数据更改自动重新构建。在现代前端应用程序中管理应用程序状态本质上是一项复杂的任务,而 Flet 的“老式”方法对于没有前端经验的程序员来说可能更有吸引力。

visible 每个控件都有默认visible属性true- 控件在页面上呈现。设置visible为false完全阻止控件(及其所有子控件,如果有)在页面画布上呈现。隐藏控件无法通过键盘或鼠标进行聚焦或选择,并且它们不会发出任何事件。

disabled 每个控件都有默认disabled的属性false- 控件及其所有子控件均已启用。 disabled属性主要与TextField、Dropdown、Checkbox、 按钮等数据输入控件一起使用。但是,disabled可以设置为父控件,其值将递归地传播到所有子控件。

例如,如果您有一个具有多个输入控件的表单,您可以disabled单独为每个控件设置属性:

python
first_name = ft.TextField()
last_name = ft.TextField()
first_name.disabled = True
last_name.disabled = True
page.add(first_name, last_name)

或者您可以将表单控件放入容器中,例如Column,然后disabled为列设置:

python
first_name = ft.TextField()
last_name = ft.TextField()
c = ft.Column(controls=[
    first_name,
    last_name
])
c.disabled = True
page.add(c)

控制 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()

    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()
        first_name.focus()

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

ft.app(target=main)

在方法的一开始main(),我们创建了三个将在按钮的处理程序中使用的控件on_click:两个TextField用于名字和姓氏,一个Column- 用于问候消息的容器。main()我们创建控件并设置其所有属性,并在方法结束时在page.add()调用中使用它们的引用(变量)。

当添加越来越多的控件和事件处理程序时,将所有控件定义保留在一个位置变得很困难,因此它们会分散在整个main()主体中。浏览一下page.add()参数,很难想象(如果没有在 IDE 中不断跳转到变量定义)最终的形式会是什么样子:

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

是first_name一个 TextField,它是否设置了自动对焦?问候语是aRow还是a Column?

Flet 提供了Ref实用程序类,它允许定义对控件的引用,在事件处理程序中使用该引用,并稍后在构建树时设置对真实控件的引用。这个想法来自React。

要定义新的类型化控件引用:

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

要访问引用的控件(控件取消引用),请使用Ref.current属性:

python
# empty first name
first_name.current.value = ""

要将控件分配给引用,请将Control.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]()

    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()
        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.ElevatedButton("Say hello!", on_click=btn_click),
        ft.Column(ref=greetings),
    )

ft.app(target=main)

现在我们可以清楚地看到page.add()页面的结构及其构建的所有控件。

是的,逻辑变得有点冗长,因为您需要添加.current.访问引用的控制,但这是个人喜好的问题

遇码MeetCoding 开源技术社区