Calculator Tutorial
This tutorial demonstrates building a multi-platform Calculator app using the Flet framework in Python. It covers basic Flet concepts including page layout, control addition, reusable UI components, event handling, and app publishing.
Requirements
flet package installed (pip install flet)Core Concepts & Implementation Steps
1. Getting Started
flet as ft.main function that accepts page: ft.Page.page.add() to add controls to the page.ft.run(main).Example hello.py:
import flet as ftdef main(page: ft.Page):
page.add(ft.Text(value="Hello, world!"))
ft.run(main)
2. Adding Page Controls
ft.Text control for displaying results.ft.Button controls for numbers and operations.3. Building Page Layout
ft.Row to arrange controls horizontally.ft.Column to stack rows vertically.ft.Container for styling.#### Container Styling
width: Sets the width of the container.bgcolor: Sets the background color (e.g., ft.Colors.BLACK).border_radius: Applies rounded corners (e.g., ft.BorderRadius.all(20)).padding: Adds internal spacing.content: Takes a control (typically ft.Column) to hold the calculator's rows.#### Styled Controls (Custom Buttons)
To achieve specific visual styles for buttons, custom controls inheriting from ft.Button are created:
CalcButton (Base Class):**expand: int = 1: Controls button sizing within its row.
DigitButton:**bgcolor: ft.Colors.WHITE_24
* color: ft.Colors.WHITE
ActionButton:**bgcolor: ft.Colors.ORANGE
* color: ft.Colors.WHITE
ExtraActionButton:**bgcolor: ft.Colors.BLUE_GREY_100
* color: ft.Colors.BLACKThese custom buttons are then used within ft.Row controls inside the main ft.Container's ft.Column.
4. Reusable UI Components
CalculatorApp class) for reusability.5. Handling Events
button_clicked).on_click property of button controls.e.control.content to identify the clicked button's label.result.value) and call page.update() to refresh the UI.6. Publishing Your App
flet build command to package the application.Full Code Example (Calculator App)
from dataclasses import field
import flet as ftdef main(page: ft.Page):
page.title = "Calc App"
result = ft.Text(value="0", color=ft.Colors.WHITE, size=20)
# Custom button classes
@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
# Event handler
def button_clicked(e):
data = e.control.content
print(f"Button clicked with data = {data}")
if data == "AC":
result.value = "0"
# TODO: Implement calculator logic here
page.update()
# Helper to create buttons with event handler
def create_button(button_type, text, **kwargs):
btn = button_type(content=text, on_click=button_clicked, **kwargs)
return btn
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=[
create_button(ExtraActionButton, "AC"),
create_button(ExtraActionButton, "+/-"),
create_button(ExtraActionButton, "%", expand=1), # Adjusted expand for consistency
create_button(ActionButton, "/"),
],
alignment=ft.MainAxisAlignment.SPACE_BETWEEN
),
ft.Row(
controls=[
create_button(DigitButton, "7"),
create_button(DigitButton, "8"),
create_button(DigitButton, "9"),
create_button(ActionButton, "*"),
],
alignment=ft.MainAxisAlignment.SPACE_BETWEEN
),
ft.Row(
controls=[
create_button(DigitButton, "4"),
create_button(DigitButton, "5"),
create_button(DigitButton, "6"),
create_button(ActionButton, "-"),
],
alignment=ft.MainAxisAlignment.SPACE_BETWEEN
),
ft.Row(
controls=[
create_button(DigitButton, "1"),
create_button(DigitButton, "2"),
create_button(DigitButton, "3"),
create_button(ActionButton, "+"),
],
alignment=ft.MainAxisAlignment.SPACE_BETWEEN
),
ft.Row(
controls=[
create_button(DigitButton, "0", expand=2),
create_button(DigitButton, "."),
create_button(ActionButton, "="),
],
alignment=ft.MainAxisAlignment.SPACE_BETWEEN
),
]
)
)
)
if __name__ == "__main__":
ft.run(main)