Presentationer Slide 1/1

Kap 5.6 · Miniuppgift

Kombinera GUI, API och databas

Bygg ett skämtregister med tkinter, requests och SQLite.

Mål

Tre tekniker i ett program

  • tkinter skapar gränssnittet.
  • requests hämtar data från ett API.
  • sqlite3 sparar data lokalt.
  • Funktioner kopplar ihop hela flödet.

Projektet

Skämtregister

  1. Hämta ett skämt från ett API.
  2. Visa skämtet i GUI:t.
  3. Spara skämtet i SQLite.
  4. Visa alla sparade skämt.

Helhetsbild

Så samarbetar delarna

Klick i tkinter

startar en Pythonfunktion

requests → API → JSON

hämtar ett nytt skämt

sqlite3 → skamt.db

sparar skämtet permanent

Förberedelse

Installera requests

python3 -m pip install requests

tkinter och sqlite3 ingår normalt i Python.

requests behöver vanligtvis installeras separat.

Hela programmet · del 1

Import och databas

import tkinter as tk
import requests
import sqlite3

conn = sqlite3.connect("skamt.db")
cursor = conn.cursor()
cursor.execute("""
    CREATE TABLE IF NOT EXISTS skamt (
        id INTEGER PRIMARY KEY AUTOINCREMENT,
        setup TEXT,
        punchline TEXT
    )
""")
conn.commit()

senaste_skamt = None

Hela programmet · del 2

Programmets funktioner

def hamta_skamt():
    global senaste_skamt
    response = requests.get(
        "https://official-joke-api.appspot.com/random_joke"
    )

    if response.status_code == 200:
        data = response.json()
        skamt_label.config(
            text=f"{data['setup']} - {data['punchline']}"
        )
        senaste_skamt = (data["setup"], data["punchline"])

def spara_skamt():
    if senaste_skamt:
        cursor.execute(
            "INSERT INTO skamt (setup, punchline) VALUES (?, ?)",
            senaste_skamt
        )
        conn.commit()
        skamt_label.config(text="Skämtet sparat!")

Hela programmet · del 3

Visa sparade skämt och skapa GUI

def visa_skamt():
    cursor.execute("SELECT * FROM skamt")
    rader = cursor.fetchall()
    output = "\n".join(
        [f"{rad[1]} - {rad[2]}" for rad in rader]
    )
    if len(output) > 300:
        output = output[:300] + "..."
    skamt_label.config(text=output)

root = tk.Tk()
root.title("Skämtregister")

tk.Button(root, text="Hämta skämt", command=hamta_skamt).pack()
tk.Button(root, text="Spara skämt", command=spara_skamt).pack()
tk.Button(root, text="Visa alla skämt", command=visa_skamt).pack()

skamt_label = tk.Label(root, text="", wraplength=300, justify="left")
skamt_label.pack()

root.mainloop()

Databas

Skapa fil och tabell

conn = sqlite3.connect("skamt.db")
cursor = conn.cursor()

connect() öppnar databasen eller skapar filen.

CREATE TABLE IF NOT EXISTS skamt (...)

Tabellen skapas bara om den inte redan finns.

Tillstånd

Kom ihåg det senast hämtade skämtet

senaste_skamt = None

None betyder att inget skämt har hämtats ännu.

senaste_skamt = (
    data["setup"],
    data["punchline"]
)

Efter API-anropet innehåller variabeln en tuple med två texter.

global

Funktionen ändrar den yttre variabeln

def hamta_skamt():
    global senaste_skamt

global anger att funktionen ska ändra variabeln utanför funktionen.

Utan raden skulle en tilldelning skapa en lokal variabel med samma namn.

API

Hämta och tolka ett skämt

response = requests.get(url)

if response.status_code == 200:
    data = response.json()

requests.get() skickar en GET-förfrågan.

200 betyder att anropet lyckades.

json() gör svaret till Pythondata.

Visa resultat

API-data blir text i GUI:t

skamt_label.config(
    text=f"{data['setup']} - {data['punchline']}"
)

setup innehåller skämtets första del.

punchline innehåller poängen.

config() ändrar texten i etiketten.

Spara

Spara bara när ett skämt finns

if senaste_skamt:
    cursor.execute(
        "INSERT INTO skamt "
        "(setup, punchline) VALUES (?, ?)",
        senaste_skamt
    )
    conn.commit()

? är platshållare för värdena i tuplen.

commit() sparar ändringen permanent.

Läsa

Hämta alla databasrader

cursor.execute("SELECT * FROM skamt")
rader = cursor.fetchall()

fetchall() ger en lista med alla rader.

output = "\n".join(
    [f"{rad[1]} - {rad[2]}" for rad in rader]
)

Varje rad görs om till en text på en egen rad.

GUI

Tre knappar, tre funktioner

tk.Button(
    root,
    text="Hämta skämt",
    command=hamta_skamt
).pack()

Varje knapp får sin funktion via command.

  • hamta_skamt använder API:et.
  • spara_skamt skriver till databasen.
  • visa_skamt läser från databasen.

Prova själv

Interaktiv simulering: skämtregister

Skämtregister

Vad händer i koden?

Programmet har skapat skamt.db och väntar på ett knapptryck.

Hela flödet

Från klick till databas

  1. Användaren klickar på Hämta skämt.
  2. API-svaret visas och sparas i senaste_skamt.
  3. Användaren klickar på Spara skämt.
  4. INSERT lägger in tuplen i databasen.
  5. commit() sparar ändringen.
  6. Visa alla läser och visar raderna.

Testning

Kontrollera fler än normalfallet

  • Klicka på Spara innan något har hämtats.
  • Spara flera olika skämt.
  • Spara samma skämt flera gånger.
  • Starta om programmet och visa sparade skämt.
  • Testa när API:et eller nätverket inte svarar.

Förbättring

API-anropet behöver felhantering

try:
    response = requests.get(url, timeout=10)
    response.raise_for_status()
    data = response.json()
except requests.exceptions.RequestException:
    skamt_label.config(
        text="Kunde inte hämta ett skämt."
    )

Grundkoden visar flödet. Den robustare versionen hanterar nätverks- och HTTP-fel.

Bygg vidare

Nästa steg

  • lägg till ett sökfält
  • ta bort valda skämt
  • visa skämten i en lista
  • förhindra dubbletter
  • stäng databasanslutningen korrekt
  • kontrollera tabellen med SQLite Viewer

Sammanfattning

Kom ihåg

  • GUI:t startar funktioner genom knapptryck.
  • API:et levererar data som JSON.
  • En tuple håller det senast hämtade skämtet.
  • SQLite sparar skämt mellan programkörningar.
  • Funktionerna binder ihop GUI, API och databas.
  • Testning och felhantering behövs för ett robust program.