Skip to content

计算器教程


在本教程中,你将逐步学习如何使用 Flet 框架在 Python 中创建一个计算器应用,并将其发布为桌面、移动或网页应用。虽然该应用非常简单,但它却是一个多平台应用,具有类似于 iPhone 计算器应用的 UI 界面:

计算器应用

你可以在这里找到在线 Demo。

在本教程中,我们将涵盖创建 Flet 应用的所有基本概念:构建页面布局、添加控件、制作可重用的 UI 界面组件、处理事件以及发布选项。

Flet 入门

要使用 Flet 在 Python 中创建多平台应用,你不需要了解 HTML、CSS 或 JavaScript,但确实需要掌握 Python 的基础知识和面向对象编程。

在创建你的第一个 Flet 应用之前,你需要安装并配置开发环境,这需要 Python 3.10 或更高版本以及 flet 包。

安装好 Flet 后,让我们创建一个简单的 Hello World 应用

创建 hello.py 文件并写入以下内容:

hello.py

python
import flet as ft

def main(page: ft.Page):
    page.add(ft.Text(value="Hello, world!"))

ft.run(main)

运行该应用,你将看到一个包含问候语的新窗口:

hello-world

添加页面控件

现在,你已经准备好创建一个计算器应用了。

首先,你需要一个 Text 控件来显示计算结果,以及几个用于显示数字和操作的 Button 按钮。

创建 calc.py 文件并写入以下内容:

提示

你可以在这里在线尝试

calc.py

python
import flet as ft


def main(page: ft.Page):
    page.title = "Calc App"
    result = ft.Text(value="0")

    page.add(
        result,
        ft.Button("AC"),
        ft.Button("+/-"),
        ft.Button("%"),
        ft.Button("/"),
        ft.Button("7"),
        ft.Button("8"),
        ft.Button("9"),
        ft.Button("*"),
        ft.Button("4"),
        ft.Button("5"),
        ft.Button("6"),
        ft.Button("-"),
        ft.Button("1"),
        ft.Button("2"),
        ft.Button("3"),
        ft.Button("+"),
        ft.Button("0"),
        ft.Button("."),
        ft.Button("="),
    )


if __name__ == "__main__":
    ft.run(main)

运行该应用,你将看到类似下面的页面:

calc1

构建页面布局

现在,让我们把文本和按钮排列到 6 个水平 Row 中。

calc.py 的内容替换为以下代码:

提示

你可以在这里在线尝试

calc.py

python
import flet as ft


def main(page: ft.Page):
    page.title = "Calc App"
    result = ft.Text(value="0")

    page.add(
        ft.Row(controls=[result]),
        ft.Row(
            controls=[
                ft.Button("AC"),
                ft.Button("+/-"),
                ft.Button("%"),
                ft.Button("/"),
            ]
        ),
        ft.Row(
            controls=[
                ft.Button("7"),
                ft.Button("8"),
                ft.Button("9"),
                ft.Button("*"),
            ]
        ),
        ft.Row(
            controls=[
                ft.Button("4"),
                ft.Button("5"),
                ft.Button("6"),
                ft.Button("-"),
            ]
        ),
        ft.Row(
            controls=[
                ft.Button("1"),
                ft.Button("2"),
                ft.Button("3"),
                ft.Button("+"),
            ]
        ),
        ft.Row(
            controls=[
                ft.Button("0"),
                ft.Button("."),
                ft.Button("="),
            ]
        ),
    )


if __name__ == "__main__":
    ft.run(main)

运行该应用,你将看到类似下面的页面:

calc2

使用 Container 进行装饰

为了在计算器周围添加黑色背景和圆角边框,我们将使用 Container 控件。由于 Container 只能装饰一个控件,我们需要将所有 6 行包裹进一个垂直的 Column 中,并将其作为容器的 content

container-layout

以下是向页面添加容器的代码:

python
    page.add(
        ft.Container(
            width=350,
            bgcolor=ft.Colors.BLACK,
            border_radius=ft.BorderRadius.all(20),
            padding=20,
            content=ft.Column(
                controls= [],
            )
        )
    )
样式化控件

为了完成程序的 UI 部分,我们需要更新结果文本和按钮的样式,使其看起来与 iPhone 计算器应用类似。

对于结果文本,让我们指定它的颜色和大小属性:

python
result = ft.Text(value="0", color=ft.Colors.WHITE, size=20)

对于按钮,如果我们再次查看我们想要实现的 UI,有 3 种类型的按钮:

  1. 数字按钮(Digit Buttons):它们有深灰色背景和白色文本,所有按钮大小相同,但 0 按钮除外,它的宽度是其他按钮的两倍。
  2. 操作按钮(Action Buttons):它们有橙色背景和白色文本,所有按钮大小相同。
  3. 辅助操作按钮(Extra Action Buttons):它们有浅灰色背景和黑色文本,所有按钮大小相同。

这些按钮将在程序中多次使用,因此我们将创建自定义的**样式化控件(Styled Controls)**来复用代码。

由于所有这些类型都应该继承自 Button 类,并具有共同的 text 和 expand 属性,因此让我们创建一个父类 CalcButton

python
@ft.control
class CalcButton(ft.Button):
    expand: int = 1

现在,让我们为这三种类型的按钮创建子类:

python
@ft.control
class DigitButton(CalcButton):
    bgcolor: ft.Colors = ft.Colors.WHITE_24
    color: ft.Colors = ft.Colors.WHITE

@ft.control
class ActionButton(CalcButton):
    bgcolor: ft.Colors = ft.Colors.ORANGE
    color: ft.Colors = ft.Colors.WHITE

@ft.control
class ExtraActionButton(CalcButton):
    bgcolor: ft.Colors = ft.Colors.BLUE_GREY_100
    color: ft.Colors = ft.Colors.BLACK

我们现在将在 Container 中使用这些新类来创建多行按钮:

python
content = ft.Column(
            controls=[
                ft.Row(
                    controls=[result],
                    alignment=ft.MainAxisAlignment.END,
                ),
                ft.Row(
                    controls=[
                        ExtraActionButton(content="AC"),
                        ExtraActionButton(content="+/-"),
                        ExtraActionButton(content="%"),
                        ActionButton(content="/"),
                    ]
                ),
                ft.Row(
                    controls=[
                        DigitButton(content="7"),
                        DigitButton(content="8"),
                        DigitButton(content="9"),
                        ActionButton(content="*"),
                    ]
                ),
                ft.Row(
                    controls=[
                        DigitButton(content="4"),
                        DigitButton(content="5"),
                        DigitButton(content="6"),
                        ActionButton(content="-"),
                    ]
                ),
                ft.Row(
                    controls=[
                        DigitButton(content="1"),
                        DigitButton(content="2"),
                        DigitButton(content="3"),
                        ActionButton(content="+"),
                    ]
                ),
                ft.Row(
                    controls=[
                        DigitButton(content="0", expand=2),
                        DigitButton(content="."),
                        ActionButton(content="="),
                    ]
                ),
            ]
        )
完整代码

以下是该阶段的完整代码:

提示

你可以在这里在线尝试

calc.py

python
from dataclasses import field
import flet as ft


def main(page: ft.Page):
    page.title = "Calc App"
    result = ft.Text(value="0", color=ft.Colors.WHITE, size=20)

    @ft.control
    class CalcButton(ft.Button):
        expand: int = field(default_factory=lambda: 1)

    @ft.control
    class DigitButton(CalcButton):
        bgcolor: ft.Colors = ft.Colors.WHITE_24
        color: ft.Colors = ft.Colors.WHITE

    @ft.control
    class ActionButton(CalcButton):
        bgcolor: ft.Colors = ft.Colors.ORANGE
        color: ft.Colors = ft.Colors.WHITE

    @ft.control
    class ExtraActionButton(CalcButton):
        bgcolor: ft.Colors = ft.Colors.BLUE_GREY_100
        color: ft.Colors = ft.Colors.BLACK

    page.add(
        ft.Container(
            width=350,
            bgcolor=ft.Colors.BLACK,
            border_radius=ft.BorderRadius.all(20),
            padding=20,
            content=ft.Column(
                controls=[
                    ft.Row(controls=[result], alignment=ft.MainAxisAlignment.END),
                    ft.Row(
                        controls=[
                            ExtraActionButton(content="AC"),
                            ExtraActionButton(content="+/-"),
                            ExtraActionButton(content="%"),
                            ActionButton(content="/"),
                        ]
                    ),
                    ft.Row(
                        controls=[
                            DigitButton(content="7"),
                            DigitButton(content="8"),
                            DigitButton(content="9"),
                            ActionButton(content="*"),
                        ]
                    ),
                    ft.Row(
                        controls=[
                            DigitButton(content="4"),
                            DigitButton(content="5"),
                            DigitButton(content="6"),
                            ActionButton(content="-"),
                        ]
                    ),
                    ft.Row(
                        controls=[
                            DigitButton(content="1"),
                            DigitButton(content="2"),
                            DigitButton(content="3"),
                            ActionButton(content="+"),
                        ]
                    ),
                    ft.Row(
                        controls=[
                            DigitButton(content="0", expand=2),
                            DigitButton(content="."),
                            ActionButton(content="="),
                        ],
                    ),
                ]
            ),
        )
    )


if __name__ == "__main__":
    ft.run(main)

这正是我们想要的效果!

calc3

可重用的 UI 组件

虽然你可以继续在 main 函数中编写你的应用,但最佳实践是创建一个可重用的 UI 组件(Reusable UI Component)

想象一下,你正在开发一个应用头部、一个侧边栏菜单,或者是一个将作为更大项目一部分的 UI(例如,在 Flet 中,我们将在一个更大的展示所有 Flet 框架示例的 “Gallery” 应用中使用这个计算器应用)。

即使你现在还没有想到这样的用途,我们仍然建议你在创建所有 Flet 应用时都要考虑到组合性和可重用性。

为了使计算器应用成为一个可重用的组件,我们将把它的状态和展示逻辑封装在一个独立的 CalculatorApp 类中。

你可以从这里复制此步骤的完整代码。

尝试其他做法

尝试在页面中添加两个 CalculatorApp 组件:

python
# 创建应用实例
calc1 = CalculatorApp()
calc2 = CalculatorApp()

# 将应用的根控件添加到页面中
page.add(calc1, calc2)

处理事件

现在让我们让计算器开始工作。我们将为所有按钮使用相同的事件处理器,并使用 content 属性来区分点击不同按钮时执行的操作。

我们将在 CalculatorClass 中定义 button_clicked 方法,并将其传递给每个按钮。以下是 on_click 事件处理器,它会在点击 “AC” 按钮时重置 Text 的值:

python
def button_clicked(self, e):
    data = e.control.content
    print(f"按下了按钮,数据为 = {data}")
    if data == "AC":
        self.result.value = "0"

通过类似的方法,button_clicked 方法将根据每个按钮的 content 属性来处理不同的计算器操作。你可以从这里复制本步骤的完整代码。

运行应用并查看其实际运行效果:

calc-app2

发布你的应用

恭喜!你已经使用 Flet 创建了计算器应用,它看起来棒极了!现在是时候向世界分享你的应用了!

使用 flet build 命令,Flet Python 应用及其所有依赖项可以被打包成一个独立的独立可执行分发包。

按照这些说明将你的计算器应用打包为桌面可执行程序、移动应用安装包或网页应用。

总结

在本教程中,你学习了如何:

  • 创建一个简单的 Flet 应用;
  • 使用可重用的 UI 组件
  • 使用 Column、Row 和 Container 控件设计 UI 布局;
  • 处理事件;
  • 将你的 Flet 应用发布到多个平台;

要进一步阅读,你可以探索 controlsexamples


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