🔢 Counter App
Xây dựng ứng dụng Counter với Declarative UI. ⏱️ 15 phút
🎯 Mục tiêu
Phần tiêu đề “🎯 Mục tiêu”Tạo ứng dụng đếm số với:
- Nút tăng (+) và giảm (-)
- Hiển thị số hiện tại
- Nút reset về 0
- UI đẹp với Card và styling
📋 Yêu cầu
Phần tiêu đề “📋 Yêu cầu”- Đã cài đặt Flet (
pip install 'flet[all]') - Hiểu cơ bản về Components và use_state
🚀 Bắt đầu
Phần tiêu đề “🚀 Bắt đầu”Bước 1: Tạo file project
Phần tiêu đề “Bước 1: Tạo file project”Tạo file counter_app.py:
import flet as ft
def main(page: ft.Page): page.title = "Counter App" page.add(ft.Text("Hello"))
ft.run(main)Chạy thử: flet run counter_app.py
Bước 2: Tạo Counter Component
Phần tiêu đề “Bước 2: Tạo Counter Component”import flet as ft
@ft.componentdef Counter(): count, set_count = ft.use_state(0)
return ft.Text(str(count), size=48)
def main(page: ft.Page): page.title = "Counter App" page.vertical_alignment = ft.MainAxisAlignment.CENTER page.horizontal_alignment = ft.CrossAxisAlignment.CENTER page.add(Counter())
ft.run(main)Bước 3: Thêm các nút điều khiển
Phần tiêu đề “Bước 3: Thêm các nút điều khiển”import flet as ft
@ft.componentdef Counter(): count, set_count = ft.use_state(0)
return ft.Column([ ft.Text(str(count), size=72, weight=ft.FontWeight.BOLD), ft.Row([ ft.IconButton( ft.Icons.REMOVE_CIRCLE, icon_size=40, icon_color=ft.Colors.RED, on_click=lambda _: set_count(count - 1), ), ft.IconButton( ft.Icons.ADD_CIRCLE, icon_size=40, icon_color=ft.Colors.GREEN, on_click=lambda _: set_count(count + 1), ), ], alignment=ft.MainAxisAlignment.CENTER), ], horizontal_alignment=ft.CrossAxisAlignment.CENTER)
def main(page: ft.Page): page.title = "Counter App" page.vertical_alignment = ft.MainAxisAlignment.CENTER page.horizontal_alignment = ft.CrossAxisAlignment.CENTER page.add(Counter())
ft.run(main)Bước 4: Thêm nút Reset và styling
Phần tiêu đề “Bước 4: Thêm nút Reset và styling”import flet as ft
@ft.componentdef Counter(): count, set_count = ft.use_state(0)
# Xác định màu dựa trên giá trị def get_color(): if count > 0: return ft.Colors.GREEN elif count < 0: return ft.Colors.RED return ft.Colors.GREY
return ft.Card( content=ft.Container( content=ft.Column([ ft.Text("COUNTER", size=16, color=ft.Colors.GREY_500), ft.Text( str(count), size=72, weight=ft.FontWeight.BOLD, color=get_color(), ), ft.Row([ ft.IconButton( ft.Icons.REMOVE_CIRCLE, icon_size=50, icon_color=ft.Colors.RED_400, tooltip="Giảm", on_click=lambda _: set_count(count - 1), ), ft.IconButton( ft.Icons.REFRESH, icon_size=40, icon_color=ft.Colors.GREY_400, tooltip="Reset", on_click=lambda _: set_count(0), ), ft.IconButton( ft.Icons.ADD_CIRCLE, icon_size=50, icon_color=ft.Colors.GREEN_400, tooltip="Tăng", on_click=lambda _: set_count(count + 1), ), ], alignment=ft.MainAxisAlignment.CENTER), ], horizontal_alignment=ft.CrossAxisAlignment.CENTER, spacing=10), padding=40, ), elevation=5, )
def main(page: ft.Page): page.title = "Counter App" page.vertical_alignment = ft.MainAxisAlignment.CENTER page.horizontal_alignment = ft.CrossAxisAlignment.CENTER page.bgcolor = ft.Colors.GREY_100 page.add(Counter())
ft.run(main)✅ Code hoàn chỉnh
Phần tiêu đề “✅ Code hoàn chỉnh”import flet as ft
@ft.componentdef Counter(): count, set_count = ft.use_state(0)
def get_color(): if count > 0: return ft.Colors.GREEN elif count < 0: return ft.Colors.RED return ft.Colors.GREY_700
return ft.Card( content=ft.Container( content=ft.Column([ ft.Text("COUNTER", size=14, color=ft.Colors.GREY_500, weight=ft.FontWeight.W_500), ft.Container( content=ft.Text( str(count), size=80, weight=ft.FontWeight.BOLD, color=get_color(), ), padding=ft.padding.symmetric(vertical=20), ), ft.Row([ ft.FilledTonalButton( content=ft.Icon(ft.Icons.REMOVE, size=30), style=ft.ButtonStyle(shape=ft.CircleBorder(), padding=15), on_click=lambda _: set_count(count - 1), ), ft.OutlinedButton( content=ft.Icon(ft.Icons.REFRESH, size=24), style=ft.ButtonStyle(shape=ft.CircleBorder(), padding=10), on_click=lambda _: set_count(0), ), ft.FilledTonalButton( content=ft.Icon(ft.Icons.ADD, size=30), style=ft.ButtonStyle(shape=ft.CircleBorder(), padding=15), on_click=lambda _: set_count(count + 1), ), ], alignment=ft.MainAxisAlignment.CENTER, spacing=20), ], horizontal_alignment=ft.CrossAxisAlignment.CENTER), padding=50, ), elevation=8, )
def main(page: ft.Page): page.title = "Counter App" page.vertical_alignment = ft.MainAxisAlignment.CENTER page.horizontal_alignment = ft.CrossAxisAlignment.CENTER page.bgcolor = ft.Colors.BLUE_GREY_50 page.add(Counter())
ft.run(main)🎯 Thử thách mở rộng
Phần tiêu đề “🎯 Thử thách mở rộng”- Step input - Cho phép chọn bước nhảy (1, 5, 10)
- Min/Max limit - Giới hạn khoảng cho phép
- History - Lưu lịch sử các giá trị
- Multiple counters - Nhiều counter độc lập
📝 Kiến thức ôn tập
Phần tiêu đề “📝 Kiến thức ôn tập”@ft.component- Tạo component tái sử dụngft.use_state()- Quản lý state localft.Card,ft.Container- Styling UI- Event handlers với lambda
⏭️ Tiếp theo
Phần tiêu đề “⏭️ Tiếp theo”Tuyệt! Tiếp tục với Mini Project: Todo List để xây dựng ứng dụng phức tạp hơn.