Lezione 5: Form e liste — ListView, GridView, ScrollView
Obiettivi
Section titled “Obiettivi”- 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
1. Form con validazione
Section titled “1. Form con validazione”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 automaticopage.scroll = ft.ScrollMode.ALWAYS # Scroll sempre visibilepage.scroll = ft.ScrollMode.HIDDEN # Scroll nascosto ma funzionanteEsempio: pagina lunga
Section titled “Esempio: pagina lunga”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 apage.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)ListView dinamica (aggiungere elementi)
Section titled “ListView dinamica (aggiungere elementi)”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)Differenze: Column vs ListView
Section titled “Differenze: Column vs ListView”| Caratteristica | Column | ListView |
|---|---|---|
| Scroll | Manuale (scroll=...) | Integrato |
| Performance | OK per pochi elementi | Ottima per tanti elementi |
| Riciclo elementi | No | Sì (solo quelli visibili) |
| Quando usarla | < 20 elementi | > 20 elementi o dinamico |
4. GridView — Griglia di elementi
Section titled “4. GridView — Griglia di elementi”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à di GridView
Section titled “Proprietà di GridView”| Proprietà | Descrizione |
|---|---|
max_extent | Larghezza massima per ogni cella |
child_aspect_ratio | Rapporto larghezza/altezza (1=quadrato, 1.5=rettangolo largo) |
spacing | Spazio verticale tra elementi |
run_spacing | Spazio orizzontale tra colonne |
expand | Occupa tutto lo spazio disponibile |
controls | Lista dei figli |
5. Esempio guidato: Rubrica contatti
Section titled “5. Esempio guidato: Rubrica contatti”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)6. Tabella riassuntiva
Section titled “6. Tabella riassuntiva”| Componente | Uso principale | Scroll |
|---|---|---|
Column | Pochi elementi statici | Opzionale |
ListView | Liste dinamiche, molti elementi | Integrato |
GridView | Griglia di elementi | Integrato |
ScrollView | Contenuto lungo in colonna | Integrato |
7. Esercizio autonomo
Section titled “7. Esercizio autonomo”🎯 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:
- Un titolo “La mia Galleria”
- Un form con:
- Campo “Titolo immagine”
- Campo “URL immagine” (usa
ft.icons.IMAGEcome icona)
- Un bottone “Aggiungi” che inserisce un nuovo elemento nella GridView
- La griglia (GridView) che mostra le immagini aggiunte come card:
- Icona rappresentativa (usa
ft.icons.PHOTOoft.icons.IMAGE) - Titolo sotto l’icona
- Icona rappresentativa (usa
- Un bottone “Rimuovi ultima” che elimina l’ultima immagine aggiunta
Specifiche aggiuntive
Section titled “Specifiche aggiuntive”- 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
Suggerimenti
Section titled “Suggerimenti”- Usa
ft.GridView(max_extent=200, child_aspect_ratio=1, spacing=10, run_spacing=10) - Per la card, usa
ft.Containerconcontent=ft.Column([icona, titolo]) - Per l’icona usa
ft.Icon(ft.icons.PHOTO, size=40, color="grey") - Ricorda
page.update()dopo ogni modifica