Seite 1 von 1

Funktion periodisch aufrufen

Verfasst: Donnerstag 16. November 2017, 23:38
von DB7WN
Hallo allerseits,
Ich möchte einen Wert aus einer MYSQL-Datenbank lesen und in einem kleinen Fenster auf dem Desktop darstellen.
Im Prinzip funktioniert das auch. Ich will allerdings diese Datenabfrage periodisch wiederholen (alle 5min), weil sich der Wert ändert. (hier mal zum testen auf 3 sec gestellt)
An dieser Stelle komme ich nicht weiter. Das Programm bleibt scheinbar in der while-Schleife stehen. Ich hab mal gelesen, dass bei solchen Verzögerungen in der mainloop diese dann nicht richtig funktioniert.
Wie soll ich diese periodische Abfrage bewerkstelligen?

Code: Alles auswählen

from tkinter import *
import mysql.connector
import time
from time import sleep


def abfrage():
        connection = mysql.connector.connect (host = 'xxx', user = 'xxx', password = 'xxx', database = 'xxx')
        cursor = connection.cursor()
        #die Tabelle 'wsensor' wird absteigend sortiert nach Datum und eine Zeile wird selectiert (LIMIT1) - d.h. dann 'die letzte Zeile'
        cursor.execute("SELECT*from wsensor ORDER BY jahr DESC, monat DESC, tag DESC, stunde DESC, minute DESC LIMIT 1")
        #das 7. Element der Zeile wird gelesen und in einen string gewandelt
        wert = str(cursor.fetchone()[6])    
        connection.close()
        labeltext="Temperatur :", wert, " °C"
        return labeltext

fenster = Tk()
fenster.geometry("120x50+1230+640")
fenster.title("")
label0=Label(fenster, text = "Leinenborn")
label0.place(x=10, y=0)
label=Label(fenster)
label.place(x=10, y=15)

while 1:
      labeltext = abfrage()
      label.configure(text = labeltext)
      sleep (3)

fenster.mainloop()

Re: Funktion periodisch aufrufen

Verfasst: Freitag 17. November 2017, 01:25
von __deets__
Du darfst bei GUIs nicht den mainloop blockieren. Sonst kann sie keine Ereignisse wie zB Mausklicks verarbeiten.

Stattdessen musst du selbst Ereignisse erzeugen, mit der after-Methode. Damit kannst du periodisch Code ausführen lassen. Es finden sich hier im Forum Tonnen von Diskussionen genau dazu.

Re: Funktion periodisch aufrufen

Verfasst: Freitag 17. November 2017, 07:59
von Sirius3
@DB7WN: zusätzlich noch Bemerkungen zum Code: *-Importe vermeiden. `import tkinter as tk` und alle tk-Namen per `tk.` ansprechen. Eingerückt wird immer mit 4 Leerzeichen pro Ebene, am besten Editor so einstellen, dass das Automatisch beim Drücken von TAB passiert.
Wer füllt die Datenbank? Datenbanken kennen TIMESTAMP, das sollte als Datum benutzt werden und nicht 5 einzelne Felder.
Falls sich mal die Reihenfolge der Datenbankfelder ändert, funktioniert das Programm nicht mehr, deshalb immer "SELECT FELD1,FELD2 ..." statt * benutzen. Wenn Du nur den Sensorwert willst, holst Du Dir auch nur den Sensorwert.
Auch wenn Tk mit allem möglichen zurecht kommt, solltest Du nur Strings als Labeltext verwenden und den per .format erzeugen.

Re: Funktion periodisch aufrufen

Verfasst: Freitag 17. November 2017, 11:29
von DB7WN
Danke, Sirius3, für die Hinweise. Dass die "while 1" - Schleife in der mainloop Unsinn ist, ist mir mittlerweile selbst aufgefallen.
Eine "after-methode" hab ich noch nicht gekannt, ich werd mich mal drum kümmern.
Die Datenbank wird von mir selbst gefüttert, ich hab also alles im Griff, was da passiert.
Deine anderen grundsätzlichen Anmerkungen scheinen mir sehr nützlich zu sein.

Re: Funktion periodisch aufrufen

Verfasst: Freitag 17. November 2017, 22:37
von DB7WN
Also mit "label.after(....)" hab ich's jetzt hingekriegt. Mir ist aufgefallen, dass ich jedes beliebige Widget da benutzen kann. Es geht auch mit "fenster.after(...) oder label0.after(...). Es muss ja nur dafür gesorgt werden, dass die Funktion "abfrage()" wiederholt wird. Aber dass das mit beliebigen Widgets geht kommt mir trotzdem etwas unlogisch vor.
Ist es jetzt so, dass der Programmablauf nur innerhalb der Funktion geschieht? Könnte jetzt trotzdem innerhalb des (root)-fensters sich noch anderes abspielen, oder wird die mainloop garnicht mehr abgearbeitet?
Die Sache mit dem Import von Bibliotheken hab ich schon öfter gelesen, aber noch nicht richtig verinnerlicht - ich probier meistens aus, wie's geht.
Die Datenbank habe ich irgendwann mal selbst angelegt, hab aber versäumt einen Timestamp mitzuführen. Wenn ich mal Lust habe, versuche ich mal den nachträglich zuzufügen, das zeitliche sortieren ist jetzt wirklich etwas umständlich.
Wie Du siehst, bin ich ein Hobby-Programmierer, der nichts so wirklich richtig kann, lerne aber doch gerne mal was dazu. Zum Glück brauche ich das nicht wirklich.

Code: Alles auswählen

def abfrage():
        connection = mysql.connector.connect (host = 'xxx', user = 'xxx', password = '2yRnuvhb8', database = 'db_351346_2')
        cursor = connection.cursor()
        #die Tabelle 'wsensor' wird absteigend sortiert nach Datum und eine Zeile wird selectiert (LIMIT1) - d.h. dann 'die letzte Zeile'
        cursor.execute("SELECT*from wsensor ORDER BY jahr DESC, monat DESC, tag DESC, stunde DESC, minute DESC LIMIT 1")
        #das 7. Element der Zeile wird gelesen und in einen string gewandelt
        wert = str(cursor.fetchone()[6])
        label.config(text = time.time())
        connection.close()
        label.after(3000,abfrage)
        

fenster = Tk()
fenster.geometry("120x50+1130+640")
fenster.title("")

label0=Label(fenster, text = "Leinenborn")
label0.place(x=10, y=0)

label=Label(fenster)
label.place(x=10, y=15)

abfrage()

fenster.mainloop()

Re: Funktion periodisch aufrufen

Verfasst: Samstag 18. November 2017, 05:18
von __deets__
Nein, MainLoop ist immer noch relevant. Nur dein timer Code wird Regelmäßig ausgeführt. Warum das auf jedem Widget geht ist mir auch nicht klar. Es schadet aber auch nicht.

Du solltest auch davon absehen, jedes mal die Datenbankverbindung zu öffnen. Das reicht einmal am Anfang des programmlaufs. Danach reichen dann neue cursor bzw. eine Transaktion.