@Finn_h: Das Problem kann ich zwar praktisch nicht nachvollziehen, bei mir ”funktioniert” das, aber Du hast da eine „race condition“ wo nebenläufig ein Code läuft der `Temperatur` definiert und ein Code läuft der `Temperatur` in der GUI aktualisiert. Und wenn der Code, der die GUI aktualisiert, schneller zu dem Punkt kommt `Temperatur` zu verwenden als der andere Code zu dem Punkt kommt `Temperatur` das erste mal zu definieren, dann gibt es logischerweise den Fall das man einen `NameError` bekommt.
``global`` definiert keine Variablen, das deklariert die nur als (modul)global. Das heisst das sorgt dafür das die Funktion den Namen nicht lokal, sondern im Modulnamensraum sucht. Da existiert sie aber erst wenn ihr dort auch tatsächlich ein Wert zugewiesen wurde.
Soweit zur Erklärung allerdings verwendet man sowieso kein ``global``. Bei objektorientierter Programmierung (OOP) gibt es da auch keinen Grund zu, und die braucht man im Grunde bei jeder nicht-trivialen GUI. Also vergiss das es ``global`` gibt.
Weitere Anmerkungen zum Code: Auf Modulebene gehört nur Code der Konstanten, Funktionen, und Klassen definiert. Das Hauptprogramm steht üblicherweise in einer Funktion die `main()` heisst.
Funktionen und Methoden bekommen alles was sie ausser Konstanten benötigen als Argument(e) übergeben. Das ist dann der Punkt an dem man bei GUI-Programmierung Closures und/oder Klassen braucht. `display_Temp()` benötigt also mindestens das Label auf dem die Temperatur angezeigt wird als Argument und die Queue über die die Temperatur übermittelt wird. Und die Queue muss auch dem Thread übergeben werden.
Namen werden in Python klein_mit_unterstrichen geschrieben. Ausnahmen sind Konstanten (KOMPLETT_GROSS) und Klassen (MixedCase). Namen sollten keine Abkürzungen oder unsinnige Prä- oder Postfixe enthalten und auch nicht nummeriert werden. `my_` ist beispielsweise unsinnig. Das hat keinerlei Informationsgehalt.
Der Thread braucht gar keinen Namen, da nach dem erstellen und starten nicht mehr auf das Objekt zugegriffen wird.
Man sollte Threads eigentlich immer mit ``daemon=True`` starten, es sei denn man will wirklich, dass das Programm mit dem Thread weiterläuft, auch wenn der Hauptthread beendet ist. Was man gerade bei GUI-Programmen nicht möchte, denn wenn man das Fenster schliesst, läuft dann immer noch der Thread weiter, und wenn man das Programm nicht von einer Konsole aus gestartet hat, dann ist das nur noch über die Prozessverwaltung des Betriebssystems zu beenden. Oder man macht ein Konsolenfenster auf, sucht sich die Prozess-ID heraus, und verwendet das entsprechende Konsolenkommando zum beenden von Prozessen. Beides ist unnötig aufwändig.
`Temp_label` enthält eine Abkürzung die zu allem Überfluss auch sehr häufig für „Temporär” steht. Wenn man `temperature` meint, sollte man das auch schreiben.
`Temp_find` klingt komisch weil die Temperatur ja nicht „gefunden“ wird, sondern gelesen. Ist dann auch von der Reihenfolge der Worte eher so Yoda.
`serialNum` ist eine Konstante, sollte also `SERIAL_NUMBER` heissen, und vielleicht worde es Sinn machen auch noch die Information in den Namen zu packen *wofür* das eine Seriennummer ist.
Und diese Konstante sollte man im Code dann vielleicht auch verwenden.
Dateien sollte man wo möglich mit der ``with``-Anweisung öffnen. Und bei Textdateien immer explizit die Kodierung angeben.
Der `float()`-Aufruf bei der literalen 1000 ist überflüssig.
Zwischenstand:
Code: Alles auswählen
#!/usr/bin/env python3
import queue
import random
import threading
import time
import tkinter as tk
from pathlib import Path
TEMPERATURE_SENSOR_SERIAL_NUMBER = "28-01192139d25e"
def display_temperature(label, temperatures_queue):
try:
while True:
label["text"] = temperatures_queue.get_nowait()
except temperatures_queue.Empty:
pass
label.after(5000, display_temperature, label, temperatures_queue)
def read_temperature(temperature_queue):
while True:
# second_line = (
# Path(
# "/sys/bus/w1/devices",
# TEMPERATURE_SENSOR_SERIAL_NUMBER,
# "w1_slave",
# )
# .read_text(encoding="utf-8")
# .split("\n")[1]
# )
# temperature = float(second_line.split(" ")[9][2:]) / 1000
# temperature_queue.put(temperature)
temperature = random.randint(25, 30)
temperature_queue.put(temperature)
print(temperature)
time.sleep(5)
def main():
window = tk.Tk()
window.title("Temperatur")
font = ("Arial", 20)
tk.Label(window, text="Die aktuelle Temperatur beträgt: ", font=font).grid(
row=0, column=0
)
temperature_label = tk.Label(window, font=font)
temperature_label.grid(row=0, column=1)
temperature_queue = queue.Queue()
threading.Thread(
target=read_temperature, args=[temperature_queue], daemon=True
).start()
display_temperature(temperature_label, temperature_queue)
window.mainloop()
if __name__ == "__main__":
main()
Falls das lesen der Temperatur schnell geht und das auch nicht hängen bleiben kann, könnte man sich den Thread sparen und das in einem `after()`-Rückruf erledigen.