Skip to content

Lezione 15: Progetto — Sviluppo e completamento

  • Implementare tutte le funzionalità del progetto
  • Aggiungere persistenza dei dati
  • Testare e correggere bug
  • Rifinire l’interfaccia utente

Segui questa roadmap per completare il progetto:

LEZIONE 15a (6 ore): Core funzionalità
└── Implementa le funzionalità principali (CRUD)
└── Aggiungi persistenza JSON
└── Testa che tutto funzioni
LEZIONE 15b (6 ore): UI e rifiniture
└── Migliora l'aspetto (tema, colori, layout)
└── Aggiungi SnackBar per feedback
└── Gestisci casi limite (input vuoto, errori)
└── Test finale su tutte le funzionalità

2. Pattern CRUD: le 4 operazioni fondamentali

Section titled “2. Pattern CRUD: le 4 operazioni fondamentali”

Quasi tutti i progetti hanno bisogno di operazioni CRUD (Create, Read, Update, Delete):

# CREATE — Aggiungere
def aggiungi(e):
if input.value:
dati.append({
"id": len(dati) + 1,
"testo": input.value,
"creato": str(datetime.date.today()),
})
salva_dati(dati)
ricostruisci_ui()
mostra_snack("✅ Elemento aggiunto")
input.value = ""
page.update()
# READ — Leggere (già fatto: carica_dati all'avvio)
dati = carica_dati()
# UPDATE — Modificare
def modifica(idx):
nuovo_valore = input_modifica.value
if nuovo_valore:
dati[idx]["testo"] = nuovo_valore
salva_dati(dati)
ricostruisci_ui()
mostra_snack("✏️ Modificato!")
# DELETE — Eliminare
def elimina(idx):
dati.pop(idx)
salva_dati(dati)
ricostruisci_ui()
mostra_snack("🗑️ Eliminato!")

3. Pattern: Aggiornare la UI dopo modifiche

Section titled “3. Pattern: Aggiornare la UI dopo modifiche”

La funzione ricostruisci_ui() è fondamentale:

def ricostruisci_ui():
"""Ricostruisce tutta la UI partendo dai dati correnti."""
contenuto.controls.clear()
if not dati:
contenuto.controls.append(
ft.Text("Nessun elemento. Aggiungine uno!", color="grey", italic=True)
)
page.update()
return
for i, elemento in enumerate(dati):
card = ft.Container(
content=ft.Row([
ft.Text(elemento["testo"], expand=True),
ft.IconButton(ft.icons.EDIT, on_click=lambda e, idx=i: modifica(idx)),
ft.IconButton(ft.icons.DELETE, on_click=lambda e, idx=i: elimina(idx)),
]),
padding=15,
bgcolor="white",
border_radius=10,
margin=5,
)
contenuto.controls.append(card)
page.update()

Aggiungi questa utility al tuo progetto:

def mostra_snack(page, messaggio, colore="green"):
"""Mostra una notifica temporanea."""
page.snack_bar = ft.SnackBar(
content=ft.Text(messaggio),
open=True,
bgcolor=colore,
duration=3000,
)
page.update()

Esempio d’uso:

mostra_snack(page, "✅ Salvato!", "green")
mostra_snack(page, "❌ Errore!", "red")
mostra_snack(page, "⚠️ Campo vuoto!", "orange")

def chiedi_elimina(idx):
def conferma(e):
dialog.open = False
dati.pop(idx)
salva_dati(dati)
ricostruisci_ui()
mostra_snack(page, "🗑️ Eliminato!")
page.update()
dialog = ft.AlertDialog(
title=ft.Text("Conferma"),
content=ft.Text("Sei sicuro di voler eliminare questo elemento?"),
actions=[
ft.TextButton("Annulla", on_click=lambda e: chiudi(dialog)),
ft.ElevatedButton("Elimina", on_click=conferma, color="red"),
],
actions_alignment=ft.MainAxisAlignment.END,
)
page.dialog = dialog
dialog.open = True
page.update()
def chiudi(dialog):
dialog.open = False
page.update()

Proteggi le operazioni critiche:

def carica_dati_sicura():
try:
if os.path.exists(FILE_DATI):
with open(FILE_DATI, "r", encoding="utf-8") as f:
return json.load(f)
except json.JSONDecodeError:
mostra_snack(page, "⚠️ File dati danneggiato. Ricreo...", "orange")
except Exception as ex:
mostra_snack(page, f"❌ Errore: {ex}", "red")
return []
def salva_dati_sicura(dati):
try:
# Prima salva in un file temporaneo
temp_file = FILE_DATI + ".tmp"
with open(temp_file, "w", encoding="utf-8") as f:
json.dump(dati, f, indent=2, ensure_ascii=False)
# Poi rinomina (operazione atomica)
os.replace(temp_file, FILE_DATI)
except Exception as ex:
mostra_snack(page, f"❌ Errore salvataggio: {ex}", "red")

Usa questa checklist per assicurarti che il progetto sia completo:

  • L’app fa ciò che ho descritto nel wireframe
  • Tutti i bottoni funzionano
  • La navigazione tra schermate funziona
  • I dati vengono salvati su file JSON
  • Alla riapertura, i dati sono ancora lì
  • Layout pulito (padding, spacing adeguati)
  • Card con ombre e angoli arrotondati
  • Messaggi di feedback (SnackBar) per azioni importanti
  • Messaggio quando la lista è vuota
  • Colori coerenti in tutta l’app
  • Se l’input è vuoto, mostra un messaggio (non si blocca)
  • Se il file JSON è danneggiato, l’app non si blocca
  • Conferma prima di eliminare elementi
  • Gestione errori per API (se presenti)
  • Tema chiaro/scuro
  • Filtri o ricerca
  • Ordinamento elementi
  • Animazioni
  • Icone appropriate

import flet as ft
import json
import os
import datetime
FILE_DATI = "progetto_dati.json"
# --- FUNZIONI DI UTILITY ---
def carica_dati():
try:
if os.path.exists(FILE_DATI):
with open(FILE_DATI, "r", encoding="utf-8") as f:
return json.load(f)
except json.JSONDecodeError:
pass
return []
def salva_dati(dati):
with open(FILE_DATI, "w", encoding="utf-8") as f:
json.dump(dati, f, indent=2, ensure_ascii=False)
def mostra_snack(page, msg, colore="green"):
page.snack_bar = ft.SnackBar(ft.Text(msg), open=True, bgcolor=colore, duration=3000)
page.update()
# --- MAIN APP ---
def main(page: ft.Page):
page.title = "Il Mio Progetto"
page.padding = 20
page.theme_mode = ft.ThemeMode.LIGHT
page.scroll = ft.ScrollMode.AUTO
dati = carica_dati()
contenuto = ft.Column(spacing=10, expand=True)
# --- FUNZIONI DELL'APP ---
def ricostruisci_ui():
"""Ricostruisce la UI dai dati."""
contenuto.controls.clear()
if not dati:
contenuto.controls.append(
ft.Text("Nessun elemento presente", italic=True, color="grey")
)
page.update()
return
for i, elem in enumerate(dati):
# Personalizza in base al tuo progetto
card = ft.Container(
content=ft.Text(f"{i+1}. {elem.get('testo', '')}"),
padding=15, bgcolor="white", border_radius=10,
shadow=ft.BoxShadow(blur_radius=5, color=ft.colors.GREY_300),
)
contenuto.controls.append(card)
page.update()
# --- INTERFACCIA ---
page.add(
ft.Text("📱 Il Mio Progetto", size=28, weight="bold"),
ft.Divider(),
contenuto,
)
ricostruisci_ui()
ft.app(target=main)

Nelle prossime 2 settimane (12 ore totali):

Settimana 7 (6 ore) — Funzionalità core:

  1. Implementa le 3-5 funzionalità principali della tua app
  2. Aggiungi persistenza JSON
  3. Testa che ogni funzionalità funzioni correttamente

Settimana 8 (6 ore) — Rifiniture:

  1. Migliora UI (colori, layout, ombre)
  2. Aggiungi SnackBar per feedback
  3. Gestisci errori e casi limite
  4. Test finale completo

Ogni mezz’ora fai un test veloce: avvia l’app e verifica che non si blocchi.