tkinter after

Fragen zu Tkinter.
Antworten
Nobima
User
Beiträge: 27
Registriert: Montag 4. Januar 2016, 18:26

Guten Tag,
ich aktualisiere eine Anzeige mit after. Die sich selbst immer wieder aufrufende after-Funktion holt den Werte aus der Datenbankabfrage, die in einem separatem Modul ausgeführt wird. Der Modul muß dazu bei jeder Abholung neu ausgeführt werden um den Wert zu aktualisieren. Leider tut er das nicht. Wie kann ich das hinbekommen ?
Benutzeravatar
__blackjack__
User
Beiträge: 13116
Registriert: Samstag 2. Juni 2018, 10:21
Wohnort: 127.0.0.1
Kontaktdaten:

@Nobima: Vorweg: Die Funktion ruft sich nicht selbst auf. Das wäre dann ja Rekursion. Die Funktion sagt mit `after()`, dass sie gerne nach einer gewissen Zeit wieder aufgerufen werden möchte. Beendet sich dann. Gibt also die Kontrolle wieder an die GUI-Hauptschleife zurück. Und wird dann nach der gewünschten Zeit (±) von der GUI-Hauptschleife erneut aufgerufen.

Module werden genau einmal ausgeführt: Wenn sie das erste mal importiert werden. Und dabei darf nichts passieren ausser das Konstanten, Funktionen, und Klassen definiert werden. Beim Import darf keine Datenbankverbindung aufgebaut werden und schon gar keine Abfrage von Daten gemacht werden. Die darin definierten Funktionen kannst Du aufrufen und Objekte aus den Klassen erstellen.
„All religions are the same: religion is basically guilt, with different holidays.” — Cathy Ladman
Nobima
User
Beiträge: 27
Registriert: Montag 4. Januar 2016, 18:26

Vielen Dank für die Erläuterung. Gibt es für die Formulierung der Klasse im Modul und den Aufruf der Klassenvariablen im Hauptscript ein einfaches Beispiel (ohne Datenbank).
Benutzeravatar
Dennis89
User
Beiträge: 1156
Registriert: Freitag 11. Dezember 2020, 15:13

Hallo,

ich bin mir nicht ganz sicher was du genau für ein Bsp. möchtest. Ich habe eins zu 'after' gefunden, das ich mal geschrieben habe:

Code: Alles auswählen

#!/usr/bin/env python3

import tkinter as tk
from random import randint


class TemperaturDisplay(tk.Frame):
    def __init__(self, master):
        tk.Frame.__init__(self, master)
        tk.Label(self, text='Außentempertur:').grid(row=0, column=0)
        self.außentemperatur = tk.Label(self, text='0 °C')
        self.außentemperatur.grid(row=1, column=0)
        self.sensoren_auslesen()
        
    def außentemperatur_aktualisieren(self, außentemperatur):
        self.außentemperatur.config(text = f'{außentemperatur} °C')
        
    def sensoren_auslesen(self):
        außentemperatur = randint(0, 30)
        self.außentemperatur_aktualisieren(außentemperatur)
        self.after(1000, self.sensoren_auslesen)
                
def main():
    root = tk.Tk()
    root.title('Temperaturübersicht')
    app = TemperaturDisplay(root)
    app.pack()
    app.mainloop()
    

if __name__ == "__main__":
    main()
Grüße
Dennis
"When I got the music, I got a place to go" [Rancid, 1993]
Nobima
User
Beiträge: 27
Registriert: Montag 4. Januar 2016, 18:26

Ich versuche, mich der Aufgabe mit ganz einfachen Scripten zu nähern.
Im Haupscript steht:

Code: Alles auswählen

import tkinter as tk
import Modultest

window = tk.Tk()
window.geometry('500x180')
window.title('TEST')

foo = Modultest.Foo()
foo.periodically()

window.mainloop()
Im Modul "Modultest" steht:

Code: Alles auswählen

import tkinter as tk
import random

class Foo(tk.Tk):
    def periodically(self):
        Z = random.randint(0, 99)
        print(Z)
        self.after(2000, self.periodically)
Soweit funktioniert es periodisch. Leider wird außer dem großen Fenster noch ein kleines unerwünschtes Fenster mit dem Titel "tk #2" dargestellt. Außerdem möchte ich die Zufallszahl Z im Hauptscript verfügbar haben. Für eine Lösung bin ich dankbar.
Benutzeravatar
__blackjack__
User
Beiträge: 13116
Registriert: Samstag 2. Juni 2018, 10:21
Wohnort: 127.0.0.1
Kontaktdaten:

@Nobima: `Tk` ist ein Fenster. Wenn Du zwei davon erstellst, dann hast Du zwei Fenster. Wobei es Zufall ist, dass das reibungslos funktioniert, denn `Tk` ist *das* Hauptfenster, davon darf es immer nur eines geben. Für zusätzliche Fenster ist `Toplevel` da.

Was heisst ”zur Verfügung haben”? Wenn Du kein zweites Fenster haben möchtest, dann wird aus dem Beispiel nicht so wirklich klar was Du eigentlich machen willst. Warum ist das denn überhaupt auf zwei Module aufgeteilt?
„All religions are the same: religion is basically guilt, with different holidays.” — Cathy Ladman
Nobima
User
Beiträge: 27
Registriert: Montag 4. Januar 2016, 18:26

Ich möchte im Hauptscript die Grafik für die Anzeige von Messwerten gestalten. Zur besseren Übersicht möchte ich das periodische Abholen aktueller Messwerte aus einer Datenbank in ein anderes Modul auslagern.
Sirius3
User
Beiträge: 17754
Registriert: Sonntag 21. Oktober 2012, 17:20

Bis zu einer gewissen Länge des Programms, hast du die beste Übersicht, wenn alles in einer Datei steht.
Viel wichtiger ist eine fachliche Trennung. Funktionen, die die Datenbank abfragen, sollten nichts mit der GUI zu tun haben. Das Hauptfenster steuert die Nutzer-Interaktion, und damit auch wann die Datenbank abgefragt wird.
Nobima
User
Beiträge: 27
Registriert: Montag 4. Januar 2016, 18:26

Genau das ist meine Absicht. In meinem einfachen Testbeispiel ist die GUI im Hauptfenster (Anzeige der Zufallszahl) und die periodische Abfrage im importierten Modul (Erzeugung der Zufallszahl).
Sirius3
User
Beiträge: 17754
Registriert: Sonntag 21. Oktober 2012, 17:20

Angestossen wird das periodische Abfragen von der GUI, gehört also nicht in das Modul mit den Datenbankabfragen.
Nobima
User
Beiträge: 27
Registriert: Montag 4. Januar 2016, 18:26

Ok, daran arbeite ich gerade . Habe aber mit meinem einfachen Beispiel noch keinen Erfolg, weil ich die im Modul erzeugte
Zufallszahl nicht in die GUI zum Anzeigen bekomme.
Benutzeravatar
__blackjack__
User
Beiträge: 13116
Registriert: Samstag 2. Juni 2018, 10:21
Wohnort: 127.0.0.1
Kontaktdaten:

@Nobima: Ergebnisse von Funktionen werden über den Rückgabewert kommuniziert. Genau so kommst Du doch auch an den Zufallswert den `random.randint()` intern erzeugt.
„All religions are the same: religion is basically guilt, with different holidays.” — Cathy Ladman
Nobima
User
Beiträge: 27
Registriert: Montag 4. Januar 2016, 18:26

Die allgemeinen Hinweise sind sicher sehr hilfreich, bringen mich aber nicht weiter. Mit einem entsprechenden Code-Schnipsel, der zeigt, wie die Rückgabe des Wertes aus der Modul-Klasse ins Hauptscript erfolgt, würde mir helfen.
Benutzeravatar
Dennis89
User
Beiträge: 1156
Registriert: Freitag 11. Dezember 2020, 15:13

Hallo,

kannst du das an Hand meines Beispiels nicht? Kann es sein, dass eventuell das Allgemeine Verständnis mit dem Umgang von Klassen und Funktionen noch fehlt?
Meinst du das so?

Code: Alles auswählen

#!/usr/bin/env python3

import tkinter as tk
from random import randint


class Sensor:
    def __init__(self):
        pass

    @property
    def temperature(self):
        return randint(0, 30)


class TemperatureDisplay(tk.Frame):
    def __init__(self, master, sensor):
        tk.Frame.__init__(self, master)
        tk.Label(self, text="Außentempertur:").grid(row=0, column=0)
        self.outside_temperature = tk.Label(self, text="0 °C")
        self.outside_temperature.grid(row=1, column=0)
        self.start = tk.Button(self, text="Start", command=self.read_sensor)
        self.start.grid(row=2, column=0)
        self.sensor = sensor

    def update_temperature(self):
        self.outside_temperature.config(text=f"{self.sensor.temperature} °C")

    def read_sensor(self):
        self.update_temperature()
        self.after(1000, self.read_sensor)


def main():
    sensor = Sensor()
    root = tk.Tk()
    root.title("Temperaturübersicht")
    app = TemperatureDisplay(root, sensor)
    app.pack()
    app.mainloop()


if __name__ == "__main__":
    main()
Grüße
Dennis
"When I got the music, I got a place to go" [Rancid, 1993]
Benutzeravatar
__blackjack__
User
Beiträge: 13116
Registriert: Samstag 2. Juni 2018, 10:21
Wohnort: 127.0.0.1
Kontaktdaten:

@Nobima: Modul-Klasse und Hauptskript spielen dabei überhaupt keine Rolle. Funktionen und Rückgabewerte funktionieren überall gleich, egal in welchem Modul die Funktion definiert ist, und egal von wo aus die Funktion aufgerufen wird.

Die `randint()`-Funktion hast Du doch auch in aus einer Methode heraus aufgerufen und das Ergebnis dann in der Funktion dort verwendet, also ausgegeben. Genau so macht man das halt. Du hast da also schon ein selbst geschriebenes Beispiel was genau das macht was Du willst. Statt einer Funktion die eine Zufallszahl liefert aus einem anderen Modul zu verwenden, musst Du halt eine schreiben, die Deine Messwerte liefert, und die in dem ersten Modul verwenden, so wie Du das im zweiten Modul mit `randint()` machst.
„All religions are the same: religion is basically guilt, with different holidays.” — Cathy Ladman
Nobima
User
Beiträge: 27
Registriert: Montag 4. Januar 2016, 18:26

@Dennis89: Vielen Dank für das Beispiel. Ich habe es nun damit so hinbekommen, wie es es mir vorstelle. Ich nehme es auch zum Anlaß, mein Verständnis für Klassen zu verbessern.
Benutzeravatar
__blackjack__
User
Beiträge: 13116
Registriert: Samstag 2. Juni 2018, 10:21
Wohnort: 127.0.0.1
Kontaktdaten:

Wobei die `Sensor`-Klasse in dem Beispiel so natürlich nicht sinnvoll ist, weil es keine Klasse ist. Also jetzt bitte nicht eine Funktion sinnlos in eine Klasse stecken. Ist ja nicht Java. 😈
„All religions are the same: religion is basically guilt, with different holidays.” — Cathy Ladman
Benutzeravatar
Dennis89
User
Beiträge: 1156
Registriert: Freitag 11. Dezember 2020, 15:13

Beim Umschreiben des Codes habe ich mir schon gedacht, dass so eine Bemerkung kommen wird 😀

Wollte nur nicht mit irgendwelchen erfundenen Angaben in der __init__ verwirren.

Grüße
Dennis
"When I got the music, I got a place to go" [Rancid, 1993]
Benutzeravatar
__blackjack__
User
Beiträge: 13116
Registriert: Samstag 2. Juni 2018, 10:21
Wohnort: 127.0.0.1
Kontaktdaten:

Ja, das war mir schon klar, dass Du da ein Beispiel vereinfacht hast. Wollte nur sichergehen, dass das auch klar wird für jemanden für den Klassen noch neu sind. 🙂
„All religions are the same: religion is basically guilt, with different holidays.” — Cathy Ladman
Antworten