Skip to content

Lezione 5: Form e liste — ListView, GridView, ScrollView

  • Costruire form con più campi e validazione
  • Usare ScrollView per contenuti che non stanno nella pagina
  • Usare ListView per liste di dati dinamici
  • Usare GridView per layout a griglia

Un form raccoglie dati dall’utente. Vediamo come validarli:

import flet as ft
def main(page: ft.Page):
page.title = "Form Registrazione"
page.padding = 30
# Messaggio di errore (inizialmente nascosto)
errore = ft.Text("", color="red")
def registra(e):
# Validazione
if not nome.value:
errore.value = "Il nome è obbligatorio"
elif not email.value:
errore.value = "L'email è obbligatoria"
elif "@" not in email.value:
errore.value = "Email non valida"
elif not password.value or len(password.value) < 6:
errore.value = "Password: almeno 6 caratteri"
else:
errore.value = ""
page.add(ft.Text(f"✅ Registrato: {nome.value}", color="green"))
# Resetta i campi
nome.value = ""
email.value = ""
password.value = ""
page.update()
nome = ft.TextField(label="Nome", prefix_icon=ft.icons.PERSON)
email = ft.TextField(label="Email", prefix_icon=ft.icons.EMAIL)
password = ft.TextField(label="Password", password=True, prefix_icon=ft.icons.LOCK)
page.add(
ft.Text("Registrazione", size=28, weight="bold"),
ft.Divider(),
nome, email, password,
errore, # Messaggio di errore (vuoto = invisibile)
ft.ElevatedButton("Registrati", on_click=registra, width=200),
)
ft.app(target=main)

2. ScrollView: quando la pagina è troppo piena

Section titled “2. ScrollView: quando la pagina è troppo piena”

Se aggiungi molti componenti, Flet fa scrollare automaticamente la pagina. Ma puoi controllare esplicitamente lo scroll:

page.scroll = ft.ScrollMode.AUTO # Scroll automatico
page.scroll = ft.ScrollMode.ALWAYS # Scroll sempre visibile
page.scroll = ft.ScrollMode.HIDDEN # Scroll nascosto ma funzionante
import flet as ft
def main(page: ft.Page):
page.title = "Info App"
page.padding = 30
page.scroll = ft.ScrollMode.AUTO
elementi = []
for i in range(1, 31):
elementi.append(
ft.Container(
content=ft.Text(f"Elemento {i}", size=18),
padding=10,
bgcolor="#f0f0f0" if i % 2 == 0 else "white",
border=ft.border.all(1, "#ddd"),
)
)
page.add(
ft.Text("Elenco lungo con scroll:", size=22, weight="bold"),
*elementi, # <-- * spacchetta la lista
)
ft.app(target=main)

Nota: *elementi (l’asterisco) spacchetta la lista, passando ogni elemento come argomento separato a page.add().


3. ListView — Liste dinamiche e performanti

Section titled “3. ListView — Liste dinamiche e performanti”

ListView è come una Column con scroll integrato, ottimizzata per liste di dati.

import flet as ft
def main(page: ft.Page):
page.title = "Lista Contatti"
page.padding = 30
# Crea una ListView con scroll automatico
lista = ft.ListView(spacing=10, padding=20, height=300)
# Aggiunge elementi
for i in range(1, 21):
lista.controls.append(
ft.Container(
content=ft.Text(f"Contatto {i}"),
padding=10,
bgcolor="white",
border_radius=5,
shadow=ft.BoxShadow(blur_radius=3, color="grey"),
)
)
page.add(
ft.Text("Elenco Contatti", size=24, weight="bold"),
lista
)
ft.app(target=main)
import flet as ft
def main(page: ft.Page):
page.title = "Lista dinamica"
page.padding = 30
lista = ft.ListView(spacing=10, padding=10, height=400)
contatore = 0
def aggiungi(e):
nonlocal contatore
contatore += 1
lista.controls.append(
ft.Container(
content=ft.Text(f"Elemento aggiunto n. {contatore}"),
padding=10,
bgcolor="#e3f2fd",
border_radius=8,
)
)
page.update()
page.add(
ft.Row([ft.ElevatedButton("➕ Aggiungi elemento", on_click=aggiungi)]),
ft.Divider(),
lista,
)
ft.app(target=main)
CaratteristicaColumnListView
ScrollManuale (scroll=...)Integrato
PerformanceOK per pochi elementiOttima per tanti elementi
Riciclo elementiNoSì (solo quelli visibili)
Quando usarla< 20 elementi> 20 elementi o dinamico

GridView dispone gli elementi in una griglia con un numero di colonne variabile.

import flet as ft
def main(page: ft.Page):
page.title = "Galleria"
page.padding = 30
# Griglia: 3 colonne, scroll automatico
griglia = ft.GridView(
expand=True, # Occupa tutto lo spazio disponibile
max_extent=150, # Larghezza massima per ogni elemento
child_aspect_ratio=1, # Rapporto larghezza/altezza (1 = quadrato)
spacing=10, # Spazio tra righe
run_spacing=10, # Spazio tra colonne
)
# Colori per gli elementi
colori = ["red", "blue", "green", "amber", "purple", "teal",
"pink", "orange", "indigo", "cyan", "lime", "brown"]
for c in colori:
griglia.controls.append(
ft.Container(
content=ft.Text(c, color="white", weight="bold", size=16),
bgcolor=c,
alignment=ft.alignment.center,
border_radius=10,
)
)
page.add(
ft.Text("Tavolozza colori", size=24, weight="bold"),
griglia,
)
ft.app(target=main)
ProprietàDescrizione
max_extentLarghezza massima per ogni cella
child_aspect_ratioRapporto larghezza/altezza (1=quadrato, 1.5=rettangolo largo)
spacingSpazio verticale tra elementi
run_spacingSpazio orizzontale tra colonne
expandOccupa tutto lo spazio disponibile
controlsLista dei figli

Mettiamo tutto insieme:

import flet as ft
def main(page: ft.Page):
page.title = "Rubrica Contatti"
page.padding = 30
contatti = ft.ListView(spacing=10, padding=10, expand=True)
def aggiungi_contatto(e):
if nome.value and telefono.value:
# Crea una card contatto
card = ft.Container(
content=ft.Row([
ft.CircleAvatar(content=ft.Text(nome.value[0].upper(), color="white"), bgcolor="blue"),
ft.Column([
ft.Text(nome.value, weight="bold", size=16),
ft.Text(telefono.value, color="grey", size=14),
], spacing=2),
ft.IconButton(ft.icons.DELETE, on_click=lambda e, c=card: rimuovi_contatto(c)),
], alignment=ft.MainAxisAlignment.SPACE_BETWEEN),
padding=15,
bgcolor="white",
border_radius=10,
shadow=ft.BoxShadow(blur_radius=5, color=ft.colors.GREY_300),
)
contatti.controls.append(card)
nome.value = ""
telefono.value = ""
nome.focus()
page.update()
def rimuovi_contatto(card):
contatti.controls.remove(card)
page.update()
nome = ft.TextField(label="Nome", prefix_icon=ft.icons.PERSON, width=200)
telefono = ft.TextField(label="Telefono", prefix_icon=ft.icons.PHONE, width=200)
page.add(
ft.Text("📞 Rubrica Contatti", size=28, weight="bold"),
ft.Divider(),
ft.Row([nome, telefono, ft.ElevatedButton("➕ Aggiungi", on_click=aggiungi_contatto)]),
ft.Divider(),
ft.Text("Contatti:", size=18, weight="bold"),
contatti,
)
ft.app(target=main)

ComponenteUso principaleScroll
ColumnPochi elementi staticiOpzionale
ListViewListe dinamiche, molti elementiIntegrato
GridViewGriglia di elementiIntegrato
ScrollViewContenuto lungo in colonnaIntegrato

🎯 Esercizio: “Galleria di immagini con didascalie”

Section titled “🎯 Esercizio: “Galleria di immagini con didascalie””

Crea un file galleria.py che realizzi una galleria di immagini con:

  1. Un titolo “La mia Galleria”
  2. Un form con:
    • Campo “Titolo immagine”
    • Campo “URL immagine” (usa ft.icons.IMAGE come icona)
  3. Un bottone “Aggiungi” che inserisce un nuovo elemento nella GridView
  4. La griglia (GridView) che mostra le immagini aggiunte come card:
    • Icona rappresentativa (usa ft.icons.PHOTO o ft.icons.IMAGE)
    • Titolo sotto l’icona
  5. Un bottone “Rimuovi ultima” che elimina l’ultima immagine aggiunta
  • La griglia deve avere 3 colonne (usa max_extent=200)
  • Ogni card deve avere angoli arrotondati e ombra
  • Se si prova ad aggiungere senza titolo, mostra un messaggio di errore
  • Usa ft.GridView(max_extent=200, child_aspect_ratio=1, spacing=10, run_spacing=10)
  • Per la card, usa ft.Container con content=ft.Column([icona, titolo])
  • Per l’icona usa ft.Icon(ft.icons.PHOTO, size=40, color="grey")
  • Ricorda page.update() dopo ogni modifica