---
url: /flet/python-flet.md
description: 学习使用Python创建一个入门级的Flet应用程序
---

# 使用Python创建Flet应用程序

***

### 入门

#### 使用Python创建Flet应用程序

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

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

#### 安装flet模块

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

```sh
pip install flet
```

> :boom: 注意
> 需要升级flet模块，请运行：`pip install flet --upgrade`

要安装 Flet 预发行版（对于高级用户），请运行（初学者不推荐，请忽略）：

```python
pip install flet --pre
```

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

#### 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 发行版上安装的信息，请[参阅本指南](https://gstreamer.freedesktop.org/documentation/installing/on-linux.html?gi-language=c)。

#### WSL

Flet 应用程序可以在 WSL2 上运行。如果您遇到`cannot open display`错误，请[按照本指南](https://github.com/microsoft/wslg/wiki/Diagnosing-%22cannot-open-display%22-type-issues-with-WSLg)进行故障排除。

#### 基础应用程序结构

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

```python
import flet as ft

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

ft.app(target=main)
```

![Flet结构](/img/basic-app-structure.png)

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

典型的 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.访问引用的控制，但这是个人喜好的问题
