Popup menu component for Flet
Project description
DISPONIBLE EN INGLES Y ESPAÑOL
(VERSION INGLES)
Flet Popup Menu
A customizable and ready-to-use popup menu component for Flet applications.
It provides edit/delete dialogs, dynamic form generation for editing items, API communication,
and a flexible callback system for UI updates across modules.
🚀 Installation
pip install flet_popupmenu
Import
from flet_popupmenu import PopupMenuButton
Use
- Initialize function called "PopupMenuButton" whose arguments are:
def PopupMenuButton(
page: ft.Page,
id: int,
item_to_edit: dict = None,
alias: str = "item",
request_url: dict = None,
callback=None,
callbacks: dict = {}
):
🔍 ARGUMENTS EXPLAINED
Below is exactly what each argument does, and which ones are optional.
🔵 Required Arguments
✔ page: ft.Page
Current Flet page — required for dialogs, updates, and UI rendering.
✔ id: int
Unique identifier of the item being edited or deleted.
🟡 Optional Arguments (EXPLAINED IN DETAIL)
🟡 item_to_edit: dict = None (optional)
If provided → the popup shows a form for editing the item.
If omitted → the “edit” option is disabled automatically.
Structure example:
item_to_edit = {
"title": { "value": "Task A", "type": "text" },
"state": {
"value": 1,
"type": "dropdown",
"options": { 0: "Pending", 1: "Completed" }
}
}
If your item has no editable fields → simply pass None
🟡 alias: str = "item" (optional)
Name used in dialog messages. Examples:
-
"Task"
-
"User"
-
"Product"
If not set → defaults to "item".
🟡 request_url: dict = None (optional but RECOMMENDED)
Defines URLs for:
-
deleting the item
-
editing the item
Structure:
request_url = {
"delete": {
"url": "https://api.com/items?id=3",
"headers": headers
},
"edit": {
"url": "https://api.com/items?id=3",
"headers": headers
}
}
If omitted:
-
delete button will do nothing
-
edit button will do nothing
-
no errors will be thrown
🟡 callback=None (optional)
Function executed after a successful delete/edit.
Use it for UI refresh:
callback = refresh_tasks
⚠️ IMPORTANT: The callback must NOT require arguments. It must be a simple callable:
def refresh_tasks():
...
🟡 callbacks: dict = {} (optional, advanced)
Allows triggering multiple auxiliary functions across your app.
This is useful if deleting/editing a task also needs to:
-
reload categories
-
refresh dashboards
-
reload summary counters
callbacks={
"load_categories": {
"function": refresh_categories,
"args": []
},
"update_dashboard": {
"function": refresh_dashboard,
"args": []
}
}
If omitted → only the main callback (if any) will run.
🟡 Layout: dict = {} (optional, advanced)
Allows setting layout of popup container. Values are: top, left, right, bottom, alignment, border_radius, bg_color
layout = {
"top": int | 8,
"left": int | 0,
"right": int | 8,
"bottom": int | 0,
"alignment": "[top_right | top_center | top_left | right | center | left | bottom_right | bottom_center | bottom_left]" | ft.Alignment.top_right,
"border_radius": int # In case exists, will set width amd heght as 40x40 to cover image according background
}
🌟 FULL EXAMPLE (RECOMMENDED)
🟦 STRUCTURE
2 files:
app.py → main module
tasks.py → module where PopupMenuButton is used
🟩 1️⃣ app.py — MAIN FILE (DEFINE CALLBACKS)
# app.py
import flet as ft
from tasks import render_tasks_list
# ------- CALLBACKS DEFINED HERE IN -------
def refresh_tasks():
"""
Refreshes the task list. Gets executed after deleting/editing.
IMPORTANT: Must not require args.
"""
print("✔ refresh_tasks() executed (UI update here).")
def refresh_categories():
"""
Example of a secondary function fired from callbacks argument.
It can reload categories, counters, dashboards, etc.
"""
print("✔ refresh_categories() executed (extra UI update).")
def main(page: ft.Page):
page.title = "Callback Example"
page.vertical_alignment = ft.MainAxisAlignment.START
# ------- PASS CALLBACKS TO MODULE -------
content = render_tasks_list(
page=page,
callback_main=refresh_tasks,
callbacks_extra={
"reload_categories": {
"function": refresh_categories,
"args": []
}
}
)
page.add(content)
ft.app(target=main)
🟩 2️⃣ tasks.py — Where is used PopupMenuButton (RECIVES CALLBACKS)
# tasks.py
import flet as ft
from flet_popupmenu import PopupMenuButton
def render_tasks_list(page: ft.Page, callback_main=None, callbacks_extra=None):
"""
callback_main: main refresh function (optional)
callbacks_extra: dict with extra functions to run (optional)
"""
# Simulated API task
task = {
"id": 3,
"title": "Example Task",
"description": "This is a sample description",
"state": 1,
}
# Editable fields
item_to_edit = {
"id": { "value": task["id"], "type": "identifier", "disabled": True },
"title": { "value": task["title"], "type": "text" },
"description": { "value": task["description"], "type": "text" },
"state": {
"value": task["state"],
"type": "dropdown",
"options": {
0: "Pending",
1: "Completed",
2: "In progress"
}
}
}
# Example headers
headers = {
"Content-Type": "application/json",
"Authorization": "Bearer <token>"
}
popup = PopupMenuButton(
page=page,
id=task["id"],
item_to_edit=item_to_edit,
alias="Task",
request_url={
"delete": {
"url": f"https://example.com/tasks?id={task['id']}",
"headers": headers
},
"edit": {
"url": f"https://example.com/tasks?id={task['id']}",
"headers": headers
}
},
# 🔥 MAIN CALLBACK (typically refresh list)
callback=callback_main,
# 🔥 EXTRA CALLBACKS (optional)
callbacks=callbacks_extra
)
return ft.Column(
controls=[
ft.Text("Task List Example", size=20, weight="bold"),
ft.ListTile(
leading=ft.Icon(ft.icons.TASK),
title=ft.Text(task["title"]),
subtitle=ft.Text(task["description"]),
trailing=popup
)
]
)
🟧 What exacly happens when the user deletes or edits:
1. Popup sends a delete or an edit request to your API
2. If API responses OK → PopupMenuButton runs:
callback_main()
callbacks_extra["reload_categories"]["function"](*args)
It called by example:
✔ refresh_tasks() → to reload the list ✔ refresh_categories() → to update other system parts
3. Defenitely, the UI turns into completelly optimized.
⭐ His finallity:
-
How to separate logic across multiple files
-
How to pass a function from the main file
-
How to receive and use it within the component
-
How to use advanced callbacks
-
How to write functions without arguments
-
How to refresh the UI after actions
⚠️ COMMON MISTAKES TO AVOID
-
Do not pass callbacks that expect parameters. All functions must be def func(): ...
-
Ensure your API ends with a valid JSON response.
-
If item_to_edit is None, editing will be disabled.
-
If request_url is None, delete/edit buttons will do nothing.
-
The options key is only for dropdowns.
🧾 License
MIT License.
❤️ Contributions Welcome
Open a pull request or issue on GitHub. Suggestions and improvements are welcome!
🚀 ¿Do you even want badges for PyPI too?
Can add:
- ✔ PyPI version
- ✔ Python versions
- ✔ Wheel status
- ✔ Download counts
- ✔ License badge
- ✔ Supported OS
Only say:
👉 “Put badges too
(VERSIÓN EN ESPAÑOL)
Menú Emergente Flet
Un componente de menú emergente personalizable y listo para usar para aplicaciones Flet.
Proporciona diálogos de edición/eliminación, generación dinámica de formularios para editar elementos, comunicación con API
y un sistema flexible de callbacks para actualizar la interfaz de usuario en todos los módulos.
🚀 Instalación
pip install flet_popupmenu
Importación
from flet_popupmenu import PopupMenuButton
Uso
- Inicializa la función "PopupMenuButton" cuyos argumentos son:
def PopupMenuButton(
page: ft.Page,
id: int,
item_to_edit: dict = None,
alias: str = "item",
request_url: dict = None,
callback=None,
callbacks: dict = {}
):
🔍 EXPLICACIÓN DE ARGUMENTOS
A continuación se detalla para qué sirve cada argumento y cuáles son opcionales.
🔵 Argumentos obligatorios
✔ page: ft.Page
Página actual de Flet — necesaria para diálogos, actualizaciones y renderizado de la UI.
✔ id: int
Identificador único del elemento a editar o eliminar.
🟡 Argumentos opcionales (EXPLICADOS EN DETALLE)
🟡 item_to_edit: dict = None (opcional)
Si se proporciona → el menú muestra un formulario para editar el elemento.
Si se omite → la opción “editar” se desactiva automáticamente.
Ejemplo de estructura:
item_to_edit = {
"title": { "value": "Tarea A", "type": "text" },
"state": {
"value": 1,
"type": "dropdown",
"options": { 0: "Pendiente", 1: "Completada" }
}
}
Si tu elemento no tiene campos editables → simplemente pasa None.
🟡 alias: str = "item" (opcional)
Nombre usado en los mensajes de diálogo. Ejemplos:
- "Tarea"
- "Usuario"
- "Producto"
Si no se define → por defecto es "item".
🟡 request_url: dict = None (opcional pero RECOMENDADO)
Define URLs para:
- eliminar el elemento
- editar el elemento
Estructura:
request_url = {
"delete": {
"url": "https://api.com/items?id=3",
"headers": headers
},
"edit": {
"url": "https://api.com/items?id=3",
"headers": headers
}
}
Si se omite:
- el botón eliminar no hará nada
- el botón editar no hará nada
- no se lanzarán errores
🟡 callback=None (opcional)
Función ejecutada tras eliminar/editar exitosamente.
Úsala para refrescar la UI:
callback = refresh_tasks
⚠️ IMPORTANTE: El callback NO debe requerir argumentos. Debe ser una función simple:
def refresh_tasks():
...
🟡 callbacks: dict = {} (opcional, avanzado)
Permite disparar múltiples funciones auxiliares en tu app.
Útil si al eliminar/editar una tarea también necesitas:
- recargar categorías
- refrescar dashboards
- recargar contadores resumen
callbacks={
"load_categories": {
"function": refresh_categories,
"args": []
},
"update_dashboard": {
"function": refresh_dashboard,
"args": []
}
}
Si se omite → solo se ejecuta el callback principal (si existe).
🌟 EJEMPLO COMPLETO (RECOMENDADO)
🟦 ESTRUCTURA
2 archivos:
app.py → módulo principal
tasks.py → módulo donde se usa PopupMenuButton
🟩 1️⃣ app.py — ARCHIVO PRINCIPAL (DEFINE CALLBACKS)
# app.py
import flet as ft
from tasks import render_tasks_list
# ------- CALLBACKS DEFINIDOS AQUÍ -------
def refresh_tasks():
"""
Refresca la lista de tareas. Se ejecuta tras eliminar/editar.
IMPORTANTE: No debe requerir argumentos.
"""
print("✔ refresh_tasks() ejecutado (actualización de UI).")
def refresh_categories():
"""
Ejemplo de función secundaria disparada desde callbacks.
Puede recargar categorías, contadores, dashboards, etc.
"""
print("✔ refresh_categories() ejecutado (actualización extra de UI).")
def main(page: ft.Page):
page.title = "Ejemplo de Callback"
page.vertical_alignment = ft.MainAxisAlignment.START
# ------- PASA CALLBACKS AL MÓDULO -------
content = render_tasks_list(
page=page,
callback_main=refresh_tasks,
callbacks_extra={
"reload_categories": {
"function": refresh_categories,
"args": []
}
}
)
page.add(content)
ft.app(target=main)
🟩 2️⃣ tasks.py — Donde se usa PopupMenuButton (RECIBE CALLBACKS)
# tasks.py
import flet as ft
from flet_popupmenu import PopupMenuButton
def render_tasks_list(page: ft.Page, callback_main=None, callbacks_extra=None):
"""
callback_main: función principal de refresco (opcional)
callbacks_extra: dict con funciones extra a ejecutar (opcional)
"""
# Tarea simulada de API
task = {
"id": 3,
"title": "Tarea Ejemplo",
"description": "Esta es una descripción de muestra",
"state": 1,
}
# Campos editables
item_to_edit = {
"id": { "value": task["id"], "type": "identifier", "disabled": True },
"title": { "value": task["title"], "type": "text" },
"description": { "value": task["description"], "type": "text" },
"state": {
"value": task["state"],
"type": "dropdown",
"options": {
0: "Pendiente",
1: "Completada",
2: "En progreso"
}
}
}
# Ejemplo de headers
headers = {
"Content-Type": "application/json",
"Authorization": "Bearer <token>"
}
popup = PopupMenuButton(
page=page,
id=task["id"],
item_to_edit=item_to_edit,
alias="Tarea",
request_url={
"delete": {
"url": f"https://example.com/tasks?id={task['id']}",
"headers": headers
},
"edit": {
"url": f"https://example.com/tasks?id={task['id']}",
"headers": headers
}
},
# 🔥 CALLBACK PRINCIPAL (normalmente refresca la lista)
callback=callback_main,
# 🔥 CALLBACKS EXTRA (opcional)
callbacks=callbacks_extra
)
return ft.Column(
controls=[
ft.Text("Ejemplo de Lista de Tareas", size=20, weight="bold"),
ft.ListTile(
leading=ft.Icon(ft.icons.TASK),
title=ft.Text(task["title"]),
subtitle=ft.Text(task["description"]),
trailing=popup
)
]
)
🟧 ¿Qué ocurre exactamente al eliminar o editar?
1. El popup envía una petición de eliminación o edición a tu API
2. Si la API responde OK → PopupMenuButton ejecuta:
callback_main()
callbacks_extra["reload_categories"]["function"](*args)
Ejemplo de llamada:
✔ refresh_tasks() → para recargar la lista
✔ refresh_categories() → para actualizar otras partes del sistema
3. Finalmente, la UI queda completamente optimizada.
⭐ Su finalidad:
- Cómo separar la lógica en varios archivos
- Cómo pasar una función desde el archivo principal
- Cómo recibirla y usarla en el componente
- Cómo usar callbacks avanzados
- Cómo escribir funciones sin argumentos
- Cómo refrescar la UI tras acciones
⚠️ ERRORES COMUNES A EVITAR
- No pases callbacks que requieran parámetros. Todas las funciones deben ser def func(): ...
- Asegúrate de que tu API devuelva una respuesta JSON válida.
- Si item_to_edit es None, la edición estará deshabilitada.
- Si request_url es None, los botones de eliminar/editar no harán nada.
- La clave options solo es para dropdowns.
🧾 Licencia
Licencia MIT.
❤️ ¡Contribuciones bienvenidas!
Abre un pull request o issue en GitHub. ¡Se aceptan sugerencias y mejoras!
🚀 ¿Quieres también badges para PyPI?
Se pueden añadir:
- ✔ Versión PyPI
- ✔ Versiones de Python
- ✔ Estado Wheel
- ✔ Contador de descargas
- ✔ Badge de licencia
- ✔ SO soportados
Solo di:
👉 “Pon badges también”
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters