⚡ Xử lý sự kiện
Học cách xử lý các sự kiện người dùng như click, nhập liệu, hover… ⏱️ 15 phút
🎯 Mục tiêu
Phần tiêu đề “🎯 Mục tiêu”Nắm vững cách xử lý events với on_click, on_change, và các event handlers khác.
🖱️ on_click - Xử lý click
Phần tiêu đề “🖱️ on_click - Xử lý click”Trong Declarative UI, event handlers thay đổi state và UI tự động cập nhật:
import flet as ft
@ft.componentdef ClickExample(): count, set_count = ft.use_state(0)
return ft.Column([ ft.Text(f"Clicked: {count} times"), ft.ElevatedButton("Click me!", on_click=lambda _: set_count(count + 1)), ])
def main(page: ft.Page): page.add(ClickExample())
ft.run(main)Lưu ý: Dùng lambda _: (với underscore) khi không cần event object.
📝 Event Object (e)
Phần tiêu đề “📝 Event Object (e)”Khi cần thông tin từ event:
def handle_click(e): print(e.control) # Control phát sinh event print(e.control.data) # Data attribute của controlTruyền dữ liệu qua data
Phần tiêu đề “Truyền dữ liệu qua data”@ft.componentdef ItemList(): selected, set_selected = ft.use_state("")
def handle_click(e): set_selected(e.control.data)
return ft.Column([ ft.Text(f"Selected: {selected}"), ft.ElevatedButton("Item 1", data="item-1", on_click=handle_click), ft.ElevatedButton("Item 2", data="item-2", on_click=handle_click), ft.ElevatedButton("Item 3", data="item-3", on_click=handle_click), ])✏️ on_change - Xử lý thay đổi giá trị
Phần tiêu đề “✏️ on_change - Xử lý thay đổi giá trị”Dùng với TextField, Checkbox, Dropdown… trong Declarative style:
@ft.componentdef LiveSearch(): query, set_query = ft.use_state("")
return ft.Column([ ft.TextField( label="Tìm kiếm", value=query, on_change=lambda e: set_query(e.control.value), ), ft.Text(f"Bạn đang tìm: {query}") if query else ft.Container(), ])Kết quả:
flowchart LR I["🔍 Tìm kiếm: python"] --> T["Bạn đang tìm: python"] style I fill:#e3f2fd⌨️ on_submit - Khi nhấn Enter
Phần tiêu đề “⌨️ on_submit - Khi nhấn Enter”@ft.componentdef SubmitExample(): items, set_items = ft.use_state([]) input_val, set_input = ft.use_state("")
def handle_submit(_): if input_val: set_items([*items, input_val]) set_input("")
return ft.Column([ ft.TextField( label="Nhập và nhấn Enter", value=input_val, on_change=lambda e: set_input(e.control.value), on_submit=handle_submit, ), ft.Column([ft.Text(f"• {item}") for item in items]), ])🎯 on_focus / on_blur
Phần tiêu đề “🎯 on_focus / on_blur”@ft.componentdef FocusExample(): focused, set_focused = ft.use_state(False)
return ft.Container( content=ft.TextField( label="Focus me", on_focus=lambda _: set_focused(True), on_blur=lambda _: set_focused(False), ), border=ft.border.all(2, ft.Colors.GREEN if focused else ft.Colors.GREY), padding=10, border_radius=10, )🖱️ Hover Events
Phần tiêu đề “🖱️ Hover Events”@ft.componentdef HoverCard(): hovered, set_hovered = ft.use_state(False)
return ft.Container( content=ft.Text("Hover me!"), bgcolor=ft.Colors.GREEN_200 if hovered else ft.Colors.BLUE_100, padding=20, border_radius=10, on_hover=lambda e: set_hovered(e.data == "true"), )🎯 Ví dụ: Login Form (Declarative)
Phần tiêu đề “🎯 Ví dụ: Login Form (Declarative)”import flet as ft
@ft.componentdef LoginForm(): username, set_username = ft.use_state("") password, set_password = ft.use_state("") message, set_message = ft.use_state("") msg_color, set_color = ft.use_state(ft.Colors.BLACK)
def login_clicked(_): if not username: set_message("Vui lòng nhập username") set_color(ft.Colors.RED) elif not password: set_message("Vui lòng nhập password") set_color(ft.Colors.RED) else: set_message(f"Xin chào, {username}!") set_color(ft.Colors.GREEN)
def clear_clicked(_): set_username("") set_password("") set_message("")
return ft.Card( content=ft.Container( content=ft.Column([ ft.Text("Đăng nhập", size=24, weight=ft.FontWeight.BOLD), ft.TextField( label="Username", width=300, value=username, on_change=lambda e: set_username(e.control.value), ), ft.TextField( label="Password", password=True, width=300, value=password, on_change=lambda e: set_password(e.control.value), ), ft.Text(message, color=msg_color) if message else ft.Container(), ft.Row([ ft.FilledButton("Đăng nhập", on_click=login_clicked), ft.OutlinedButton("Xóa", on_click=clear_clicked), ]), ], horizontal_alignment=ft.CrossAxisAlignment.CENTER, spacing=15), padding=30, ), width=350, )
def main(page: ft.Page): page.title = "Login Form" page.vertical_alignment = ft.MainAxisAlignment.CENTER page.horizontal_alignment = ft.CrossAxisAlignment.CENTER page.add(LoginForm())
ft.run(main)Kết quả:
flowchart TD subgraph Card["Login Form"] T["🔐 Đăng nhập"] U["Username: admin"] P["Password: ••••"] M["✅ Xin chào, admin!"] B["[Đăng nhập] [Xóa]"] end T --> U --> P --> M --> B style Card fill:#ffffff style M fill:#c8e6c9📋 Bảng tổng hợp Events
Phần tiêu đề “📋 Bảng tổng hợp Events”| Event | Sử dụng với | Mô tả |
|---|---|---|
on_click |
Button, Container, Card… | Khi click |
on_change |
TextField, Checkbox, Dropdown… | Khi giá trị thay đổi |
on_submit |
TextField | Khi nhấn Enter |
on_focus |
TextField | Khi focus vào |
on_blur |
TextField | Khi mất focus |
on_hover |
Container, Card… | Khi hover chuột |
💡 So sánh Imperative vs Declarative
Phần tiêu đề “💡 So sánh Imperative vs Declarative”| Imperative (cũ) | Declarative (mới) |
|---|---|
Thay đổi control.value |
Gọi set_state(value) |
Phải gọi page.update() |
UI tự động cập nhật |
| State lưu trong controls | State lưu trong hooks |
⏭️ Bước tiếp theo
Phần tiêu đề “⏭️ Bước tiếp theo”Đã biết xử lý events! Tiếp tục với Components & Observables để học sâu hơn về Declarative UI.