Label soll sich selbständig aktualisieren

Fragen zu Tkinter.
Antworten
Benutzeravatar
XCDRiVER
User
Beiträge: 31
Registriert: Sonntag 12. Februar 2017, 19:59

Hallo Forum,
ich suche nach einer Möglichkeit, das 'self.labelData' sich mit den gesendeten Daten vom Thread
trigger selbst aktualisiert.
Wenn ich meine Funktion 'updateLabelDisplay' (Zeile 13) dauerhaft laufen lasse, hängt das Programm natürlich an der Stelle.
Was wäre der sinnvollste Weg? Einen weiteren Thread? Verwenden von Kontrollvariablen?
Ich müsste neben dem Anzeigen auf dem GUI die Werte auch noch weiter verarbeiten können.
Wenn das Thema schon mal war, bitte kurz ein Hinweis oder Link, ich konnte nichts passendes finden.
Vielen Dank

Code: Alles auswählen

from threading import Thread
from queue import Queue, Empty
from tkinter import Tk, Frame, Label
from time import sleep

class mainWindow(Frame):
    def __init__(self, q, master=None):
        super(mainWindow, self).__init__(master)
        self.pack()
        self.q = q
        self.labelData = Label(self, text="----")
        self.labelData.pack()
        self.updateLabelDisplay()

    def updateLabelDisplay(self):
        try:
            self.message = self.q.get()
        except:
            pass
##        print(self.message)
        self.labelData["text"] = self.message

class Trigger():

    def __init__(self, q):
        self.q = q
        for self.a in [9, 8, 7, 6, 5, 4, 3, 2, 1, 0]:
            self.q.put(self.a)
            sleep(2)

if __name__ == "__main__":

    q = Queue()

    trigger = Thread(target=Trigger, args=(q,))
    trigger.start()

    ## Starte Fenster ----------------------------------------------------
    root = Tk()
    fenster = mainWindow(q, master=root)
    fenster.mainloop()
    ## Ende Start Fenster
BlackJack

`updateLabelDisplay()` muss regelmässig aufgerufen werden. Schau Dir mal die `after()`-Methode auf Widgets an.

Das nackte ``except:`` ist übrigens keine gute Idee, man sollte immer nur die konkreten Ausnahmen behandeln die man auch tatsächlich erwartet und bei denen die jeweilige Behandlung auch Sinn macht.
Benutzeravatar
XCDRiVER
User
Beiträge: 31
Registriert: Sonntag 12. Februar 2017, 19:59

hallo BlackJack,
danke für den Tipp, ich denke so wie ich die Funktion eingesetzt habe ist das gedacht,
leider blockiert die Funktion meine GUI im weiteren Ablauf.
habe ich das falsch eingesetzt?

Code: Alles auswählen

from threading import Thread
from queue import Queue, Empty
from tkinter import Tk, Frame, Label
from time import sleep

class mainWindow(Frame):
    def __init__(self, q, master=None):
        super(mainWindow, self).__init__(master)
        self.pack()
        self.q = q
        self.labelData = Label(self, text="----")
        self.labelData.pack()
        self.updateLabelDisplay()

    def updateLabelDisplay(self):
        self.message = self.q.get()
        print(self.message)
        self.labelData["text"] = self.message
        self.after(250, self.updateLabelDisplay())

class Trigger():

    def __init__(self, q):
        self.q = q
        for self.a in [9, 8, 7, 6, 5, 4, 3, 2, 1, 0]:
            self.q.put(self.a)
            sleep(1)

if __name__ == "__main__":

    q = Queue()

    trigger = Thread(target=Trigger, args=(q,))
    trigger.start()

    ## Starte Fenster ----------------------------------------------------
    root = Tk()
    fenster = mainWindow(q, master=root)
    fenster.mainloop()
    ## Ende Start Fenster
Sirius3
User
Beiträge: 17741
Registriert: Sonntag 21. Oktober 2012, 17:20

@XCDRiVER: das blockiert, weil q.get blockiert. Du mußt die nonblock-Variante nehmen und prüfen, ob ein Wert in der Queue war oder nicht. Zudem darfst Du bei .after die Funktion nicht aufrufen, sondern Du darfst nur das Funktions-Objekt übergeben: self.after(250, self.updateLabelDisplay)
Benutzeravatar
XCDRiVER
User
Beiträge: 31
Registriert: Sonntag 12. Februar 2017, 19:59

hallo sirius,
danke es tut jetzt.
mein Fehler war der angesprochen falsche Funktionsaufruf.
Und nun bin ich auch an deinem zweiten Einwand angekommen.
Ich suche und probiere mal mit der nonblock Variante.
danke an euch
Benutzeravatar
XCDRiVER
User
Beiträge: 31
Registriert: Sonntag 12. Februar 2017, 19:59

So würde es ganz prima funktionieren,
ist das grundsätzlich so auch in Ordnung?
Durch das timeout Argument wirft put ja die Exception 'Empty'
aber das blockt doch noch das Programm für das timeout, denke ich?
Ist das besser nach einem Weg zu suchen wo vorher erst geprüft wird ob Daten in der queue sind und dann gelesen wird?

Code: Alles auswählen

from threading import Thread
from queue import Queue, Empty
from tkinter import Tk, Frame, Label
from time import sleep

class mainWindow(Frame):
    def __init__(self, q, master=None):
        super(mainWindow, self).__init__(master)
        self.pack()
        self.q = q
        self.labelData = Label(self, text="----")
        self.labelData.pack()
        self.updateLabelDisplay()

    def updateLabelDisplay(self):
        try:
            self.message = self.q.get(timeout=1)
##            print(self.message)
            self.labelData["text"] = self.message
        except(Empty):
            print("keine Daten")
        self.after(250, self.updateLabelDisplay)

class Trigger():

    def __init__(self, q):
        self.q = q
        for self.a in [9, 8, 7, 6, 5, 4, 3, 2, 1, 0]:
            self.q.put(self.a)
            sleep(1)
        sleep(15)
        for self.a in [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]:
            self.q.put(self.a)
            sleep(1)

if __name__ == "__main__":

    q = Queue()

    trigger = Thread(target=Trigger, args=(q,))
    trigger.start()

    ## Starte Fenster ----------------------------------------------------
    root = Tk()
    fenster = mainWindow(q, master=root)
    fenster.mainloop()
    ## Ende Start Fenster
BlackJack

@XCDRiVER: Das blockiert dann doch immer noch die GUI für ganze Sekunden. Ich würde es ohne `timeout` machen.
Benutzeravatar
XCDRiVER
User
Beiträge: 31
Registriert: Sonntag 12. Februar 2017, 19:59

hallo BlackJack,
könntest du das so gemeint haben?
Es funktioniert jedenfalls ganz prima.
Damit ist die Wartezeit vom put erst mal entfernt.
vielen Dank

Code: Alles auswählen

from threading import Thread
from queue import Queue, Empty
from tkinter import Tk, Frame, Label
from time import sleep

class mainWindow(Frame):
    def __init__(self, q, master=None):
        super(mainWindow, self).__init__(master)
        self.pack()
        self.q = q
        self.labelData = Label(self, text="----")
        self.labelData.pack()
        self.updateLabelDisplay()

    def updateLabelDisplay(self):
        try:
            self.message = self.q.get_nowait()
##            print(self.message)
            self.labelData["text"] = self.message
        except(Empty):
            print("keine Daten")
        self.after(250, self.updateLabelDisplay)

class Trigger():

    def __init__(self, q):
        self.q = q
        for self.a in [9, 8, 7, 6, 5, 4, 3, 2, 1, 0]:
            self.q.put(self.a)
            sleep(1)
        sleep(15)
        for self.a in [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]:
            self.q.put(self.a)
            sleep(1)

if __name__ == "__main__":

    q = Queue()

    trigger = Thread(target=Trigger, args=(q,))
    trigger.start()

    ## Starte Fenster ----------------------------------------------------
    root = Tk()
    fenster = mainWindow(q, master=root)
    fenster.mainloop()
    ## Ende Start Fenster
Antworten