CtrlK
BlogDocsLog inGet started
Tessl Logo

tessl/pypi-flet

Flet is a rich User Interface framework to quickly build interactive web, desktop and mobile apps in Python without prior knowledge of web technologies.

Pending
Overview
Eval results
Files

events-interaction.mddocs/

Events and Interaction

This document covers Flet's comprehensive event system and user interaction capabilities, including gesture recognition, drag and drop, keyboard/mouse events, and real-time communication.

Import

import flet as ft

Core Event System

Event Handling Basics

All Flet controls support event handling through callback functions. Events are triggered by user interactions and system changes.

Common Event Patterns:

def handle_click(e):
    # e.control - reference to the control that triggered the event
    # e.data - event-specific data
    print(f"Button clicked: {e.control.text}")

button = ft.ElevatedButton(
    "Click me!",
    on_click=handle_click
)

ControlEvent

class ControlEvent:
    """Base control event class."""
    
    control: Control  # Control that triggered the event
    name: str        # Event name
    data: str        # Event data (varies by event type)
    page: Page       # Page reference
    target: str      # Target control ID

Event

class Event:
    """Base event class for system events."""
    
    name: str   # Event name
    data: str   # Event data
    page: Page  # Page reference

Gesture Events

TapEvent

class TapEvent(ControlEvent):
    """Tap gesture event."""
    
    local_x: float      # X coordinate relative to control
    local_y: float      # Y coordinate relative to control
    global_x: float     # X coordinate relative to screen
    global_y: float     # Y coordinate relative to screen

Example:

def on_tap(e):
    print(f"Tapped at: ({e.local_x}, {e.local_y})")

ft.Container(
    content=ft.Text("Tap me"),
    width=200, height=100,
    bgcolor=ft.colors.BLUE_100,
    on_click=on_tap
)

HoverEvent

class HoverEvent(ControlEvent):
    """Hover event."""
    
    local_x: float      # X coordinate relative to control
    local_y: float      # Y coordinate relative to control
    global_x: float     # X coordinate relative to screen
    global_y: float     # Y coordinate relative to screen

Example:

def on_hover(e):
    e.control.bgcolor = ft.colors.GREY_200 if e.data == "true" else ft.colors.WHITE
    e.control.update()

ft.Container(
    content=ft.Text("Hover over me"),
    padding=20,
    bgcolor=ft.colors.WHITE,
    on_hover=on_hover
)

GestureDetector

class GestureDetector(Control):
    """Gesture detection wrapper control."""
    
    def __init__(
        self,
        content: Control = None,
        on_tap: callable = None,
        on_tap_down: callable = None,
        on_tap_up: callable = None,
        on_secondary_tap: callable = None,
        on_secondary_tap_down: callable = None,
        on_secondary_tap_up: callable = None,
        on_long_press_start: callable = None,
        on_long_press_end: callable = None,
        on_double_tap: callable = None,
        on_double_tap_down: callable = None,
        on_force_press_start: callable = None,
        on_force_press_end: callable = None,
        on_force_press_peak: callable = None,
        on_pan_start: callable = None,
        on_pan_update: callable = None,
        on_pan_end: callable = None,
        on_scale_start: callable = None,
        on_scale_update: callable = None,
        on_scale_end: callable = None,
        on_hover: callable = None,
        on_enter: callable = None,
        on_exit: callable = None,
        drag_interval: int = None,
        hover_interval: int = None,
        **kwargs
    )

Parameters:

  • content (Control, optional): Child control to wrap
  • on_tap (callable, optional): Single tap event
  • on_double_tap (callable, optional): Double tap event
  • on_long_press_start (callable, optional): Long press start event
  • on_pan_start (callable, optional): Pan gesture start event
  • on_pan_update (callable, optional): Pan gesture update event
  • on_scale_start (callable, optional): Scale gesture start event
  • on_scale_update (callable, optional): Scale gesture update event

Example:

def on_pan_update(e):
    e.control.top = max(0, e.control.top + e.delta_y)
    e.control.left = max(0, e.control.left + e.delta_x)
    e.control.update()

draggable_box = ft.GestureDetector(
    content=ft.Container(
        content=ft.Text("Drag me"),
        width=100, height=100,
        bgcolor=ft.colors.BLUE,
        border_radius=10
    ),
    on_pan_update=on_pan_update
)

Drag and Drop Events

DragStartEvent

class DragStartEvent(ControlEvent):
    """Drag operation start event."""
    
    local_x: float      # X coordinate relative to control
    local_y: float      # Y coordinate relative to control
    global_x: float     # X coordinate relative to screen
    global_y: float     # Y coordinate relative to screen
    timestamp: int      # Event timestamp

DragUpdateEvent

class DragUpdateEvent(ControlEvent):
    """Drag operation update event."""
    
    delta_x: float      # X movement delta
    delta_y: float      # Y movement delta
    local_x: float      # Current X coordinate relative to control
    local_y: float      # Current Y coordinate relative to control
    global_x: float     # Current X coordinate relative to screen
    global_y: float     # Current Y coordinate relative to screen
    primary_delta: float # Primary axis movement delta
    timestamp: int      # Event timestamp

DragEndEvent

class DragEndEvent(ControlEvent):
    """Drag operation end event."""
    
    primary_velocity: float  # Primary axis velocity
    velocity: float         # Overall velocity
    local_x: float          # Final X coordinate relative to control
    local_y: float          # Final Y coordinate relative to control
    global_x: float         # Final X coordinate relative to screen
    global_y: float         # Final Y coordinate relative to screen

Draggable

class Draggable(Control):
    """Draggable control wrapper."""
    
    def __init__(
        self,
        group: str = None,
        content: Control = None,
        content_when_dragging: Control = None,
        content_feedback: Control = None,
        **kwargs
    )

Parameters:

  • group (str, optional): Drag group identifier
  • content (Control, optional): Control to make draggable
  • content_when_dragging (Control, optional): Content shown while dragging
  • content_feedback (Control, optional): Drag feedback content

DragTarget

class DragTarget(Control):
    """Drop target for draggable controls."""
    
    def __init__(
        self,
        group: str = None,
        content: Control = None,
        on_will_accept: callable = None,
        on_accept: callable = None,
        on_leave: callable = None,
        **kwargs
    )

Example:

def on_accept_drag(e):
    # Handle dropped item
    src_control = page.get_control(e.src_id)
    print(f"Dropped: {src_control.content.value}")

# Draggable item
draggable_item = ft.Draggable(
    group="items",
    content=ft.Container(
        content=ft.Text("Drag me"),
        width=100, height=50,
        bgcolor=ft.colors.BLUE_200,
        border_radius=5
    )
)

# Drop target
drop_target = ft.DragTarget(
    group="items",
    content=ft.Container(
        content=ft.Text("Drop here"),
        width=200, height=100,
        bgcolor=ft.colors.GREEN_100,
        border_radius=5,
        alignment=ft.alignment.center
    ),
    on_accept=on_accept_drag
)

Dismissible

class Dismissible(Control):
    """Swipe-to-dismiss wrapper."""
    
    def __init__(
        self,
        content: Control = None,
        background: Control = None,
        secondary_background: Control = None,
        dismiss_direction: DismissDirection = None,
        dismiss_thresholds: dict = None,
        movement_duration: int = None,
        resize_duration: int = None,
        cross_axis_end_offset: float = None,
        on_dismiss: callable = None,
        on_update: callable = None,
        **kwargs
    )

Parameters:

  • content (Control, optional): Content to make dismissible
  • background (Control, optional): Background shown when swiping
  • dismiss_direction (DismissDirection, optional): Allowed dismiss directions
  • on_dismiss (callable, optional): Dismiss event handler
  • on_update (callable, optional): Dismiss progress update handler

Scroll Events

ScrollEvent

class ScrollEvent(ControlEvent):
    """Scroll event."""
    
    pixels: float           # Current scroll offset
    min_scroll_extent: float    # Minimum scroll extent
    max_scroll_extent: float    # Maximum scroll extent
    viewport_dimension: float   # Viewport size
    scroll_delta: float         # Scroll delta
    direction: str              # Scroll direction

Example:

def on_scroll(e):
    print(f"Scroll position: {e.pixels}")
    
    # Show/hide scroll indicator based on position
    if e.pixels > 100:
        scroll_indicator.visible = True
    else:
        scroll_indicator.visible = False
    page.update()

scrollable_content = ft.ListView(
    controls=[ft.ListTile(title=ft.Text(f"Item {i}")) for i in range(100)],
    on_scroll=on_scroll,
    auto_scroll=True
)

Keyboard Events

KeyboardEvent

class KeyboardEvent(Event):
    """Keyboard input event."""
    
    key: str            # Key identifier
    shift: bool         # Shift key pressed
    ctrl: bool          # Ctrl key pressed
    alt: bool           # Alt key pressed
    meta: bool          # Meta key pressed

Example:

def on_keyboard(e):
    if e.key == "Enter":
        handle_submit()
    elif e.key == "Escape":
        handle_cancel()
    elif e.ctrl and e.key == "s":
        handle_save()

page.on_keyboard_event = on_keyboard

Page Events

Page Lifecycle Events

def page_event_handlers(page: ft.Page):
    """Example page event handlers."""
    
    def on_route_change(e):
        """Route navigation event."""
        print(f"Route changed to: {e.route}")
    
    def on_view_pop(e):
        """View pop event."""
        print(f"View popped: {e.view}")
    
    def on_resize(e):
        """Window resize event."""
        print(f"Window resized: {page.window_width}x{page.window_height}")
    
    def on_close(e):
        """Page close event."""
        print("Page closing")
        e.page.window_destroy()
    
    page.on_route_change = on_route_change
    page.on_view_pop = on_view_pop
    page.on_resize = on_resize
    page.on_window_event = on_close

RouteChangeEvent

class RouteChangeEvent(Event):
    """Route change navigation event."""
    
    route: str          # New route
    old_route: str      # Previous route

ViewPopEvent

class ViewPopEvent(Event):
    """View pop navigation event."""
    
    view: View          # View being popped

WindowEvent

class WindowEvent(Event):
    """Window state change event."""
    
    event_type: WindowEventType     # Event type (close, focus, etc.)

Interactive Controls Events

ReorderableListView

class ReorderableListView(Control):
    """List with reorderable items."""
    
    def __init__(
        self,
        controls: List[Control] = None,
        on_reorder: callable = None,
        padding: PaddingValue = None,
        **kwargs
    )

OnReorderEvent

class OnReorderEvent(ControlEvent):
    """List reorder event."""
    
    old_index: int      # Original item index
    new_index: int      # New item index

Example:

def handle_reorder(e):
    # Reorder items in data model
    item = items.pop(e.old_index)
    items.insert(e.new_index, item)
    print(f"Moved item from {e.old_index} to {e.new_index}")

items = ["Item 1", "Item 2", "Item 3", "Item 4"]

ft.ReorderableListView(
    controls=[
        ft.ListTile(title=ft.Text(item)) for item in items
    ],
    on_reorder=handle_reorder
)

InteractiveViewer

class InteractiveViewer(Control):
    """Zoomable and pannable content viewer."""
    
    def __init__(
        self,
        content: Control = None,
        clip_behavior: ClipBehavior = None,
        pan_enabled: bool = True,
        scale_enabled: bool = True,
        double_tap_to_zoom_enabled: bool = True,
        min_scale: float = None,
        max_scale: float = None,
        interaction_end_friction_coefficient: float = None,
        on_interaction_start: callable = None,
        on_interaction_update: callable = None,
        on_interaction_end: callable = None,
        **kwargs
    )

Parameters:

  • content (Control, optional): Content to make interactive
  • pan_enabled (bool, optional): Enable panning
  • scale_enabled (bool, optional): Enable scaling/zooming
  • min_scale (float, optional): Minimum zoom scale
  • max_scale (float, optional): Maximum zoom scale

Real-time Communication

PubSub System

class PubSubClient(Control):
    """Publish-subscribe client for real-time communication."""
    
    def __init__(
        self,
        on_message: callable = None,
        **kwargs
    )
    
    def send_all(self, message: str) -> None:
        """Send message to all subscribers."""
        
    def send_all_on_topic(self, topic: str, message: str) -> None:
        """Send message to topic subscribers."""
        
    def send_others(self, message: str) -> None:
        """Send message to other subscribers."""
        
    def send_others_on_topic(self, topic: str, message: str) -> None:
        """Send message to other topic subscribers."""

Example:

def on_message_received(e):
    messages.controls.append(
        ft.Text(f"{e.topic}: {e.message}")
    )
    page.update()

pubsub = ft.PubSubClient(
    on_message=on_message_received
)

def send_message(e):
    message = message_field.value
    if message:
        pubsub.send_all_on_topic("chat", message)
        message_field.value = ""
        page.update()

message_field = ft.TextField(
    hint_text="Enter message",
    on_submit=send_message
)

messages = ft.Column(scroll=ft.ScrollMode.AUTO)

Advanced Event Patterns

Event Delegation

class EventManager:
    """Centralized event management."""
    
    def __init__(self, page):
        self.page = page
        self.handlers = {}
    
    def register_handler(self, event_type, handler):
        if event_type not in self.handlers:
            self.handlers[event_type] = []
        self.handlers[event_type].append(handler)
    
    def emit_event(self, event_type, data):
        if event_type in self.handlers:
            for handler in self.handlers[event_type]:
                handler(data)
    
    def handle_control_event(self, e):
        # Delegate to registered handlers
        self.emit_event(f"{e.control.data}_click", e)

# Usage
event_manager = EventManager(page)
event_manager.register_handler("menu_item_click", handle_menu_click)
event_manager.register_handler("button_click", handle_button_click)

Gesture Composition

def create_multi_gesture_control():
    """Control with multiple gesture handlers."""
    
    def on_tap(e):
        print("Single tap")
    
    def on_double_tap(e):
        print("Double tap")
    
    def on_long_press(e):
        print("Long press")
    
    def on_pan_update(e):
        # Handle panning
        pass
    
    def on_scale_update(e):
        # Handle pinch-to-zoom
        pass
    
    return ft.GestureDetector(
        content=ft.Container(
            content=ft.Text("Multi-gesture area"),
            width=300, height=200,
            bgcolor=ft.colors.BLUE_100,
            alignment=ft.alignment.center
        ),
        on_tap=on_tap,
        on_double_tap=on_double_tap,
        on_long_press_start=on_long_press,
        on_pan_update=on_pan_update,
        on_scale_update=on_scale_update
    )

Event Throttling

import time

class ThrottledEventHandler:
    """Throttle event handling to prevent spam."""
    
    def __init__(self, delay_ms=100):
        self.delay_ms = delay_ms
        self.last_call = 0
    
    def throttle(self, func):
        def wrapper(*args, **kwargs):
            now = time.time() * 1000
            if now - self.last_call >= self.delay_ms:
                self.last_call = now
                return func(*args, **kwargs)
        return wrapper

# Usage
throttler = ThrottledEventHandler(delay_ms=200)

@throttler.throttle
def on_scroll_throttled(e):
    # Handle scroll event with throttling
    print(f"Throttled scroll: {e.pixels}")

scrollable_list.on_scroll = on_scroll_throttled

State Management with Events

class AppState:
    """Application state management with events."""
    
    def __init__(self):
        self.data = {}
        self.listeners = {}
    
    def set_state(self, key, value):
        old_value = self.data.get(key)
        self.data[key] = value
        
        # Notify listeners
        if key in self.listeners:
            for listener in self.listeners[key]:
                listener(value, old_value)
    
    def get_state(self, key):
        return self.data.get(key)
    
    def listen(self, key, callback):
        if key not in self.listeners:
            self.listeners[key] = []
        self.listeners[key].append(callback)

# Usage
app_state = AppState()

def on_counter_change(new_value, old_value):
    counter_text.value = f"Count: {new_value}"
    page.update()

app_state.listen("counter", on_counter_change)

def increment_counter(e):
    current = app_state.get_state("counter") or 0
    app_state.set_state("counter", current + 1)

ft.ElevatedButton("Increment", on_click=increment_counter)

Performance Optimization

Efficient Event Handling

# Use event delegation for many similar controls
def create_efficient_list():
    def handle_item_click(e):
        # Single handler for all items
        item_index = int(e.control.data)
        print(f"Clicked item {item_index}")
    
    items = []
    for i in range(1000):
        item = ft.ListTile(
            title=ft.Text(f"Item {i}"),
            data=str(i),  # Store index in data
            on_click=handle_item_click
        )
        items.append(item)
    
    return ft.ListView(controls=items)

# Debounce rapid events
def debounce(delay_ms):
    def decorator(func):
        timer = None
        def wrapper(*args, **kwargs):
            nonlocal timer
            if timer:
                timer.cancel()
            timer = threading.Timer(delay_ms / 1000, func, args, kwargs)
            timer.start()
        return wrapper
    return decorator

@debounce(300)
def on_search_input(e):
    # Debounced search
    search_term = e.control.value
    perform_search(search_term)

This covers Flet's comprehensive event system and interaction capabilities, enabling you to create highly interactive and responsive applications with sophisticated user interactions.

Install with Tessl CLI

npx tessl i tessl/pypi-flet

docs

advanced-features.md

charts-visualization.md

events-interaction.md

index.md

layout-navigation.md

theming-styling.md

ui-controls.md

utilities-platform.md

tile.json