Frage zur Übergabe und Anzeige von API Inhalten

Fragen zu Tkinter.
Antworten
tomus
User
Beiträge: 1
Registriert: Mittwoch 9. Juni 2021, 08:18

Mittwoch 9. Juni 2021, 08:25

Hallo zusammen,

ich bin Anfänger und probiere gerade Wetterdaten über eine API abzurufen und mir diese in einer GUI anzeigen zu lassen. Der Abruf der Daten funktioniert soweit, allerdings bekomme ich es nicht hin, dass die Daten in meiner GUI angezeigt werden.
Ich habe den Code wieder soweit zurück gebaut, dass nach der Eingabe der Stadt in der GUI und anschließendem Beenden die Wetterdaten im Terminal ausgegeben werden.
Meine Frage ist allerdings wie ich es schaffen kann, dass die Daten in der GUI ausgegeben werden?

Wenn mir jemand weiterhelfen könnte wäre das super :) vielen Dank!
Info: den API Schlüssel habe ich abgeändert, hier hätte ich natürlich einen funktionierenden

import json
import requests
import datetime
from tkinter import *

def button_action():
entry_text = eingabefeld.get()
if (entry_text == ""):
welcome_label.config(text="Bitte gibt eine Stadt ein fuer die du das Wetter wissen willst")
else:
welcome_label.config(text="Sie fragen das Wetter fuer " + entry_text + " ab ")
return entry_text


# Ein Fenster erstellen

fenster = Tk()

fenster.title("Wetterabfrage")

# In der Ereignisschleife auf Eingabe des Benutzers warten
# Felder und Labels

# Labels

my_label = Label(fenster, text="Gib eine Stadt ein: ")
welcome_label = Label(fenster)
eingabefeld = Entry(fenster, bd=5, width=40)
welcom_button = Button(fenster, text = "Klick me", command=button_action)
exit_button = Button(fenster, text = "Beenden", command=fenster.quit)
wetterinlab = Label(fenster, text="Wetter in : ")
luftfeuchlab = Label(fenster, text="Luftfeuchtigkeit in % : ")
luftdrucklab = Label(fenster, text="Luftdruck in hpa :")
tempmaxlab = Label(fenster, text="Max. Temperatur in °C :")
tempminlab = Label(fenster, text="Min. Temperatur in °C :")
windgelab = Label(fenster, text="Windgeschwindigkeit in km/h :")
windrilab = Label(fenster, text="Windrichung :")

my_label.grid(row = 0, column = 0)
eingabefeld.grid(row = 0, column = 1)
welcom_button.grid(row = 1, column = 0)
exit_button.grid(row = 1, column = 1)
welcome_label.grid(row =2, column = 0, columnspan =2)

#Wetterdaten

wetterinlab.grid(row = 3, column = 0)
luftfeuchlab.grid(row = 4, column = 0)
luftdrucklab.grid(row = 5, column = 0)
tempmaxlab.grid(row = 6, column = 0)
tempminlab.grid(row = 7, column = 0)
windgelab.grid(row = 8, column = 0)
windrilab.grid(row = 9, column = 0)


stadt = button_action()


print(stadt)
url = "http://api.openweathermap.org/data/2.5/ ... APPID=0815" % (stadt)

print(url)

Response = requests.get(url)

WeatherData = Response.json()
#print(json.dumps(WeatherData, indent = 4, sort_keys = True))


print("Wetter in: {} ".format((WeatherData["name"])))
print("Luftfeuchtigkeit: {} %".format(WeatherData["main"]["humidity"]))
print("Luftdruck: {} hpa".format(WeatherData["main"]["pressure"]))
print("Temperatur: {}° C".format(str(WeatherData["main"]["temp"] - 273)))
print("Max. Temperatur: {}° C".format(str(WeatherData["main"]["temp_max"] - 273)))
print("Min. Temperatur: {}° C".format(str(WeatherData["main"]["temp_min"] - 273)))
print("Windgeschwindigkeit: {} m/s".format(WeatherData["wind"]["speed"]))
print("Windrichtung: {}°".format(WeatherData["wind"]["deg"]))


fenster.mainloop()
Benutzeravatar
__blackjack__
User
Beiträge: 8705
Registriert: Samstag 2. Juni 2018, 10:21
Wohnort: 127.0.0.1
Kontaktdaten:

Mittwoch 9. Juni 2021, 12:23

@tomus: `json` und `datetime` werden importiert, aber nicht verwendet.

Sternchen-Importe sind Böse™. Da holt man sich gerade bei `tkinter` fast 200 Namen ins Modul von denen nur ein kleiner Bruchteil verwendet wird. Auch Namen die gar nicht in `tkinter` definiert werden, sondern ihrerseits von woanders importiert werden. Das macht Programme unnötig unübersichtlicher und fehleranfälliger und es besteht die Gefahr von Namenskollisionen.

Auf Modulebene sollte nur Code stehen der Konstanten, Funktionen, und Klassen definiert. Das Hauptprogramm steht üblicherweise in einer Funktion die `main()` heisst.

Namen werden in Python klein_mit_unterstrichen geschrieben. Ausnahmen sind Konstanten (KOMPLETT_GROSS) und Klassen (PascalCase).

`my_*` ist in aller Regel eine unsinnige Vorsilbe wenn es nicht auch ein `our_*` oder `their_*` oder so gibt um das abzugrenzen.

Namen sollten keine kryptischen Abkürzungen enthalten. Wenn man `windgeschwindigkeits_label` meint, sollte man nicht nur `windgelab` schreiben. Man könnte auch englischsprachige Bezeichner in Betracht ziehen, weil da oft weniger lange zusammengesetzte Worte entstehen wo auch die einzelnen Worte getrennt sind, und damit oft besser lesbar sind (`wind_speed_label`).

Wenn man einen Namen nicht wirklich braucht, kann man den auch ganz einsparen und braucht sich auch keinen guten Namen ausdenken.

Warum heisst `welcom_button` so? Das hat doch überhaupt nichts mit ”Willkommen” zu tun? Auch hier: Wenn man den Namen gar nicht wirklich braucht, kann man den Code auch so schreiben, dass man da keinen Namen für braucht.

Die Beschriftung und der Name der Rückruffunktion von dieser Schaltfläche passen auch nicht so richtig zu der Aktion die da durchgeführt wird.

Die Daten für die Beschreibungen der einzelnen Werte stehen zweimal im Programm. Daten- und Codewiederholungen vermeidet man, weil das unnötig Arbeit beim schreiben und anpassen macht, und eine Fehlerquelle ist, wenn man nicht immer alle Kopien ändert, oder nicht alle gleichwertig ändert. Da würde sich beispielsweise anbieten eine Funktion zu schreiben, welche die Label, die Vorlagen, und die Werte übergeben bekommt. Die kann man dann mit leeren Werten aufrufen um den Anfangszustand zu erreichen, und dann später mit Werten die von der API abgefragt wurden.

Statt den Labels einzelne Namen zu geben, würde der Code einfacher wenn man die einfach als ”Zeilen” ansehen, und in eine Liste stecken würde.

Die `str()`-Aufrufe sind überflüssig. `format()` wandelt das schon in Zeichenketten um beim einsetzen.

Funktionen bekommen alles was sie ausser Konstanten brauchen als Argument(e) übergeben. Die `button_action()`-Funktion braucht also alle GUI-Elemente auf die abfragt und/oder verändert als Argumente. Das kann man mit `functools.partial()` oder allgemein einem „Closure“ erreichen. Für jede nicht-triviale GUI braucht man an der Stelle aber objektorientierte Programmierung (OOP).

Um Bedingungen bei ``if`` gehören keine unnötigen Klammern.

Die URL-Parameter würde man `requests.get()` als Argumente mitgeben statt sie selbst in eine Zeichenkette zu formatieren.

Es wird nicht geprüft ob die Antwort von der API im HTTP-Sinn in Ordnung ist.

Ungetestet:

Code: Alles auswählen

#!/usr/bin/env python3
import tkinter as tk
from functools import partial

import requests

APP_ID = "0815"
API_URL = "http://api.openweathermap.org/data/2.5/weather"

LINE_TEMPLATES = [
    "Wetter in: {}",
    "Luftfeuchtigkeit: {} %",
    "Luftdruck: {} hpa",
    "Temperatur: {}° C",
    "Max. Temperatur: {}° C",
    "Min. Temperatur: {}° C",
    "Windgeschwindigkeit: {} m/s",
    "Windrichtung: {}°",
]


def on_query(eingabefeld, status_label, line_labels):
    entry_text = eingabefeld.get().strip()
    if entry_text == "":
        status_label.config(
            text=(
                "Bitte gibt eine Stadt ein,"
                " für die du das Wetter wissen willst."
            )
        )
    else:
        status_label.config(text=f"Sie fragen das Wetter für {entry_text} ab.")
        response = requests.get(
            API_URL, params={"APPID": APP_ID, "q": entry_text}
        )
        response.raise_for_status()
        weather_data = response.json()
        for label, template, value in zip(
            line_labels,
            LINE_TEMPLATES,
            [
                weather_data["name"],
                weather_data["main"]["humidity"],
                weather_data["main"]["pressure"],
                weather_data["main"]["temp"] - 273,
                weather_data["main"]["temp_max"] - 273,
                weather_data["main"]["temp_min"] - 273,
                weather_data["wind"]["speed"],
                weather_data["wind"]["deg"],
            ],
        ):
            label["text"] = template.format(value)


def main():
    fenster = tk.Tk()
    fenster.title("Wetterabfrage")

    tk.Label(fenster, text="Gib eine Stadt ein: ").grid(row=0, column=0)
    eingabefeld = tk.Entry(fenster, bd=5, width=40)
    eingabefeld.grid(row=0, column=1)

    query_button = tk.Button(fenster, text="Abfragen")
    query_button.grid(row=1, column=0)
    tk.Button(fenster, text="Beenden", command=fenster.quit).grid(
        row=1, column=1
    )

    status_label = tk.Label(fenster)
    status_label.grid(row=2, column=0, columnspan=2)

    line_labels = []
    for row_index, template in enumerate(LINE_TEMPLATES, 3):
        label = tk.Label(fenster, text=template.format("?"))
        label.grid(row=row_index, column=0)
        line_labels.append(label)

    query_button["command"] = partial(
        on_query, eingabefeld, status_label, line_labels
    )
    fenster.mainloop()


if __name__ == "__main__":
    main()
long long ago; /* in a galaxy far far away */
Antworten