@Bergstern: Die Importe sollte man mal aufräumen. `threading.Timer` wird nicht verwendet. Und bei den `kivy`-Importen ist das `BoxLayout` doppelt und aus `kivy.graphics` wird zweimal importiert – das liesse sich zusammenfassen falls wirklich alles davon gebraucht wird, weil `Image`, `Window`, `BorderImage`, `Color`, und `GridLayout` werden importiert, aber auch nirgends verwendet.
Von den sechs Definitionen nach den importen werden nur zwei im Code verwendet. Die sollten komplett gross geschrieben werden, weil das Konstanten sind. Und die Klammern um die Zeichenketten machen keinen Sinn – weg damit. Wobei ich auch den Sinn dieser Konstanten nicht so ganz sehe. Sie könnten auch besser benannt sein. Ich würde jedenfalls hinter `STATION` nicht vermuten das da ein Text mit dem Wert 'keine Station' steckt.
Einige Kommentare sind schräg weil die eher wie Handlungsanweisungen aus einem Tutorial klingen. So etwas hat in einem Programm nichts zu suchen.
Der ``# Create a class for all …``-Kommentar ist falsch, weil das gar nicht das ist, was da im Code passiert. Falsche Kommentare sind im Grunde schlimmer als gar keine. Wenn keine Kommentare da sind, muss man sich am Code orientieren. Wenn Kommentare da sind, die nicht zum Code passen, dann klären die nicht den Code auf, sondern der Leser weiss nicht wer denn nun recht hat – der Code oder der Kommentar. Wenn so etwas oft genug in einer Codebasis vor kommt, dann werden auch die korrekten Kommentare wertlos, weil der Leser denen nicht mehr vertrauen kann, weil er ja auch bei den korrekten immer überprüfen muss um sie denn mit dem Code übereinstimmen oder nicht.
Die Argumente bei den `super()`-Aufrufen sind überflüssig.
`Startbildschirm.update()` hat einen sinnlosen Rückgabewert. Der Aufrufer erwartet hier keine Zeichenkette mit der Uhrzeit. Das `*args`-Argument ist der Signatur ist sehr/zu generisch. Man weiss doch dass dort *ein* Argument übergeben wird, und zwar die verstrichene Zeit seit dem letzten Aufruf.
In `Wetter` wird der Klasseninhalt in einer Reihenfolge definiert die nicht den Konventionen entspricht. Üblich ist es erst die Klassenvariablen, dann die ”magischen” Methoden, und dann normale Methoden zu definieren. Wobei `__init__()` die erste ”magische” Methode ist (sofern es kein `__new__()` gibt).
Dann definierst Du *zwei* `__init__()`-Methoden. Davon ”überlebt” nur die zweite, weil die erste durch die zweite ersetzt wird. Es kann immer nur ein Attribut mit einem gegebenen Namen existieren. Wie sollte das auch anders funktionieren?
Durch die Definition von `wetterkivy` und `stationkivy` (schlechte Namen übrigens) als Attribute auf dem Exemplar, ”verdeckst” Du die Klassenvariablen mit den gleichen Namen. Über das Exemplar erreicht man unter den Namen also nur noch die Zeichenketten, aber nicht mehr die gleichnamigen `StringProperty`-Exemplare die auf der Klasse definiert sind. Da sollten sie auch eher nicht definiert sein/werden, denn auf Klasseneben definiert man üblicherweise nur Konstanten und keine Variablen. Die werden dadurch nämlich zu globalen Variablen.
Bei `my_callback()` fehlt das `self`-Argument, oder man sollte das explizit zu einer `@staticmethod` machen.
Der Name ist schlecht. Was soll das `my_` bedeuten? Gibt es auch `our_`? Und nur `callback()` würde nichts darüber aussagen was die Funktion/Methode denn eigentlich *tut*. Das ist doch eher die Information die man als Leser haben möchte.
Die Kommentare in `my_callback()` sind nahezu alle total überflüssig weil sie nur noch mal beschreiben was sehr offensichtlich im Code sowieso schon steht. Faustregel für Kommentare: Nicht beschreiben *was* der Code macht, das steht da ja schon als Code, sondern *warum* er das macht, sofern das nicht offensichtlich ist.
Die URL wäre etwas was man eher als Konstante am Anfang des Moduls definieren würde, damit man die leicht finden und anpassen kann.
Das umbennen der Zeiten in nichtssagende und nummerierte `unix_ts*`-Namen macht keinen Sinn. Die anschliessende Rechnung wo 0 von der Zeit abgezogen wird auch nicht. Der Kommentar, dass es sich um eine Umrechnung in die MEZ-Zeitzone handelt, stimmt nur wenn das die lokale Zeitzone des Systems ist.
Das Umwandeln in einen sinnvolle(re)n Datentyp wie `datetime`-Objekte und die Formatierung als Zeichenkette für eine Ausgabe, sollte man voneinander getrennt halten.
Bei den ganzen ``if wetter…``-Konstrukten sind wieder unnötige Klammern um Zeichenkettenliterale. Das liesse sich ausserdem einfacher mit einem Wörterbuch lösen das die Englischen auf Deutsche Worte abbildet.
Bei Dateien bietet sich die ``with``-Anweisung an um das schliessen in jedem Fall sicherzustellen.
Werte und Zeichenkettenliterale mit `str()` und ``+`` zusammenstückeln ist eher BASIC als Python. Im Python gibt es dafür Zeichenkettenformatierung mit der `format()`-Methode und seit Python 3.6 auch f-Zeichenkettenliterale.
Textdateien sollten mit einem Zeilenendezeichen enden.
Das `Clock.schedule_interval()` auf *Klassenebene* hat dort sicher nichts zu suchen.
Der `screen_manager` hat auf Modulebene nichts zu suchen. Und auch `sample_app` sollte in einer Funktion verschwinden. Wobei das `sample_` in dem Namen auch gar keinen Sinn macht.
Ungetestet:
Code: Alles auswählen
#!/usr/bin/env python3
from datetime import datetime
import time
import kivy
kivy.require('1.10.1')
from kivy.app import App
from kivy.clock import Clock
from kivy.graphics import Rectangle
from kivy.lang import Builder
from kivy.properties import StringProperty
from kivy.uix.boxlayout import BoxLayout
from kivy.uix.button import Button
from kivy.uix.floatlayout import FloatLayout
from kivy.uix.label import Label
from kivy.uix.screenmanager import Screen, ScreenManager
import requests
WEATHER_API_URL = (
'http://api.openweathermap.org/data/2.5/weather?'
'&APPID=1233062e5b81bbe72ecc6d74e8e8171&q=achenkirch&units=metric'
)
WEATHER_EN_TO_DE = {
'Clouds': 'Bewoelkt',
'Rain': 'Regen',
'Clear': 'Wolkenlos',
'Snow': 'Schneefall',
}
#
# TODO Do these constants make sense?
#
STATION = 'keine Station'
UHRZEIT = 'keine Daten'
TEMPERATUR = 'keine Daten'
SONNENAUFGANG = 'keine Daten'
SONNENUNTERGANG = 'keine Daten'
WETTER = 'keine Daten'
Builder.load_string("""
<Startbildschirm>:
timeb:time_box
canvas.before:
Rectangle:
pos: self.pos
size: self.size
source: 'EuropaBeiNacht.png'
FloatLayout:
Label: # Uhrzeit und Datum
id:time_box
text:root.update()
size_hint_x: 6
pos_hint:{"center_x": 0.5, "center_y":0.95}
font_size: 30
Button:
id: Wetter
font_size: 30
color: 1, 1, 1, 1
size_hint: 0.15, 0.15
pos_hint:{"center_x": 0.2, "center_y":0.8}
background_normal: 'Kloetze.png'
text: "Wetter"
on_press:
root.manager.transition.direction = 'right'
root.manager.transition.duration = 2
root.manager.current = 'Wetter'
Button:
font_size: 30 #Schrift
color: 1,1,1, 1 #Schriftfarbe
size_hint: 0.15, 0.15
pos_hint:{"center_x": 0.15, "center_y":0.5}
background_normal: 'Kloetze.png'
text: "Frei1"
on_press:
root.manager.transition.direction = 'right'
root.manager.transition.duration = 2
root.manager.current = 'Frei1'
Button:
font_size: 30 #Schrift
color: 1,1,1, 1 #Schriftfarbe
size_hint: 0.15, 0.15
pos_hint:{"center_x": 0.2, "center_y":0.2}
background_normal: 'Kloetze.png'
text: "Frei2"
on_press:
root.manager.transition.direction = 'right'
root.manager.transition.duration = 2
root.manager.current = 'Frei2'
Button:
font_size: 30 #Schrift
color: 1,1,1, 1 #Schriftfarbe
size_hint: 0.15, 0.15
pos_hint:{"center_x": 0.8, "center_y":0.8}
background_normal: 'Kloetze.png'
text: "Frei3"
on_press:
root.manager.transition.direction = 'left'
root.manager.transition.duration = 2
root.manager.current = 'Frei3'
Button:
font_size: 30 #Schrift
color: 1,1,1, 1 #Schriftfarbe
size_hint: 0.15, 0.15
pos_hint:{"center_x": 0.85, "center_y":0.5}
background_normal: 'Kloetze.png'
text: "Frei4"
on_press:
root.manager.transition.direction = 'left'
root.manager.transition.duration = 2
root.manager.current = 'Frei4'
Button:
font_size: 30 #Schrift
color: 1,1,1, 1 #Schriftfarbe
size_hint: 0.15, 0.15
pos_hint:{"center_x": 0.8, "center_y":0.2}
background_normal: 'Kloetze.png'
text: "Frei5"
on_press:
root.manager.transition.direction = 'left'
root.manager.transition.duration = 2
root.manager.current = 'Frei5'
<Wetter>:
FloatLayout:
Button:
text: root.wetterkivy
on_press:
root.manager.transition.direction = 'left'
root.manager.current = 'Startbildschirm'
Spinner:
text: root.stationkivy
values: "Achenkirch", "Maurach", "Radfeld", "Pakostane", "Grado"
pos: 0, 0
size_hint: (0.2, 0.1)
#size: (100, 50)
<Frei1>:
BoxLayout:
Button:
text: "Frei1"
on_press:
root.manager.transition.direction = 'left'
root.manager.current = 'Startbildschirm'
<Frei2>:
BoxLayout:
Button:
text: "Frei2"
on_press:
root.manager.transition.direction = 'left'
root.manager.current = 'Startbildschirm'
<Frei3>:
BoxLayout:
Button:
text: "Frei3"
on_press:
root.manager.transition.direction = 'right'
root.manager.current = 'Startbildschirm'
<Frei4>:
BoxLayout:
Button:
text: "Frei4"
on_press:
root.manager.transition.direction = 'right'
root.manager.current = 'Startbildschirm'
<Frei5>:
BoxLayout:
Button:
text: "Frei5"
on_press:
root.manager.transition.direction = 'right'
root.manager.current = 'Startbildschirm'
""")
class Startbildschirm(Screen):
def __init__(self, **kwargs):
super().__init__(**kwargs)
Clock.schedule_interval(self.update, 1)
def update(self, _dt=None):
self.timeb.text = time.asctime()
class Wetter(Screen):
def __init__(self, **kwargs):
super().__init__(**kwargs)
self.wetterkivy = StringProperty(WETTER)
self.stationkivy = StringProperty(STATION)
Clock.schedule_interval(self.update_weather_information, 5)
@staticmethod
def update_weather_information(_dt=None):
wetterdaten = requests.get(WEATHER_API_URL).json()
stationsname = wetterdaten['name']
uhrzeit = datetime.fromtimestamp(wetterdaten['dt'])
wetter = WEATHER_EN_TO_DE[wetterdaten['weather'][0]['main']]
temperatur = wetterdaten['main']['temp']
sonnenaufgang = datetime.fromtimestamp(wetterdaten['sys']['sunrise'])
sonnenuntergang = datetime.fromtimestamp(wetterdaten['sys']['sunset'])
print(stationsname)
print(format(uhrzeit, '%H:%M:%S'))
print(temperatur)
print(wetter)
print(format(sonnenaufgang, '%H:%M:%S'))
print(format(sonnenuntergang, '%H:%M:%S'))
with open('Wetter Achenkirch.txt', 'w', encoding='utf-8') as file:
file.write('Temperatur {}\n'.format(temperatur))
class Frei1(Screen):
pass
class Frei2(Screen):
pass
class Frei3(Screen):
pass
class Frei4(Screen):
pass
class Frei5(Screen):
pass
class WetterApp(App):
def build(self):
screen_manager = ScreenManager()
screen_manager.add_widget(Startbildschirm(name='Startbildschirm'))
screen_manager.add_widget(Wetter(name='Wetter'))
screen_manager.add_widget(Frei1(name='Frei1'))
screen_manager.add_widget(Frei2(name='Frei2'))
screen_manager.add_widget(Frei3(name='Frei3'))
screen_manager.add_widget(Frei4(name='Frei4'))
screen_manager.add_widget(Frei5(name='Frei5'))
return screen_manager
def main():
app = WetterApp()
app.run()
if __name__ == '__main__':
main()