Timer mit wiederkehrender Aufgabe

Wenn du dir nicht sicher bist, in welchem der anderen Foren du die Frage stellen sollst, dann bist du hier im Forum für allgemeine Fragen sicher richtig.
Antworten
delphinis
User
Beiträge: 13
Registriert: Sonntag 5. Juli 2020, 07:34

Hallo,
möchte eine wiederkehrende Aufgabe z.B. alle 5min erledigen (zum Test nur 5s). Hab dabei mehrere Beispiele gefunden, die alle gleich aussehen, aber so nicht funktionieren.
Folgender Code sollte alle 5s das Popup-Fenster infoMsg() aufpoppen. Aber es wird nur einmal gleich beim Start aufgepoppt und dann nie mehr...

Code: Alles auswählen

from tkinter import *
import threading 
 
root = Tk()

root.geometry('100x100+-7+0')
root.configure(background='black')

def infoMsg(msg):
    popup = Tk()
    titleLabel = Label(popup, text="Info", font='Arial_bold 15', fg="red")
    titleLabel.pack(side="top", fill="both", pady=10)
    label = Label(popup, text=msg)
    label.pack(side="top", fill="both", pady=10)
    B1 = Button(popup, text="Okay", command = popup.destroy)
    B1.pack(side="top", fill="y", pady=10)
    popup.mainloop()
                
class Window(Frame):
     
    def __init__(self, master):    #globale variable an 
        Frame.__init__(self,master)
        global timer
        timer = threading.Timer(5, infoMsg("Hello"))
        timer.start()
        
app = Window(root)
app.pack(fill=BOTH, expand=YES)
root.mainloop()
__deets__
User
Beiträge: 14539
Registriert: Mittwoch 14. Oktober 2015, 14:29

Ich habe nichts von Timern gesagt. Sondern von after. Threading und GUIs funktioniert nicht.
Sirius3
User
Beiträge: 17749
Registriert: Sonntag 21. Oktober 2012, 17:20

@delphinis: benutze kein global, keine *-Importe und von Tk darf es nur eine Instanz geben und nur einen Aufruf von mainloop. Dass Du so viele kaputte Beispiele gefunden hast, ist liegt wohl daran, dass Du an der falschen Stelle gesucht hast. Hier im Forum gibt es bestimmt 100 Beiträge, wo erklärt wird, wie es richtig funktioniert.
delphinis
User
Beiträge: 13
Registriert: Sonntag 5. Juli 2020, 07:34

Ok, ich hab's nun so gelöst:
nach 5s rufe ich eine Methode auf die dann etwas tun soll, und diese startet gleich wider die after methode mit sich selbst als callback routine.
Hoffe das ist so auch korrekt, da es ja kein rekursiver aufruf im eigentlichen Sinne ist...

Code: Alles auswählen

from tkinter import *
root = Tk()
root.geometry('200x200+-7+0')

def periodic_work():
    print("doing something")
    root.after(5000, periodic_work)

class Window(Frame):
     
    def __init__(self, master):    #globale variable an 
        Frame.__init__(self,master)
        root.after(5000, periodic_work)          

app = Window(root)
root.mainloop()
__deets__
User
Beiträge: 14539
Registriert: Mittwoch 14. Oktober 2015, 14:29

So macht man das, ja.
Sirius3
User
Beiträge: 17749
Registriert: Sonntag 21. Oktober 2012, 17:20

Das ist aus den oben genannten Gründen nicht sauber gelöst.
Window ist auch nur ein Frame und kein Fenster.

Code: Alles auswählen

import tkinter as tk

class Window(tk.Frame):
    def __init__(self, master):
        super().__init__(master)
        self.after(5000, self.periodic_work)          

    def periodic_work(self):
        print("doing something")
        self.after(5000, self.periodic_work)

def main():
    root = tk.Tk()
    root.geometry('200x200+-7+0')
    app = Window(root)
    root.mainloop()

if __name__ == '__main__':
    main()
Benutzeravatar
__blackjack__
User
Beiträge: 13103
Registriert: Samstag 2. Juni 2018, 10:21
Wohnort: 127.0.0.1
Kontaktdaten:

Noch die übliche Anmerkung das `super()` hier falsch ist und nicht funktioniert weil `Frame` auch kein `super()` verwendet. Falls es das täte müsste man noch beliebige zusätzliche Argumente und Schlüsselwortargumente akzeptieren und weiterreichen. `super()` ist superkompliziert.
„All religions are the same: religion is basically guilt, with different holidays.” — Cathy Ladman
delphinis
User
Beiträge: 13
Registriert: Sonntag 5. Juli 2020, 07:34

__blackjack__ hat geschrieben: Sonntag 5. Juli 2020, 15:09 Noch die übliche Anmerkung das `super()` hier falsch ist und nicht funktioniert weil `Frame` auch kein `super()` verwendet. Falls es das täte müsste man noch beliebige zusätzliche Argumente und Schlüsselwortargumente akzeptieren und weiterreichen. `super()` ist superkompliziert.
Funktioniert doch. Aber ohne super() funktioniert es aber auch nicht (wenn man die ganze Zeile streicht). Offenbar muss man den Vorfahren doch auch initialisieren?
Benutzeravatar
__blackjack__
User
Beiträge: 13103
Registriert: Samstag 2. Juni 2018, 10:21
Wohnort: 127.0.0.1
Kontaktdaten:

@delphinis: Natürlich muss man die `__init__()` der Basisklasse aufrufen, aber mit `super()` ist das halt falsch. Und ”funktioniert doch” stimmt halt nur solange bis das dann mal jemand für das benutzen will wofür es eigentlich da ist.
„All religions are the same: religion is basically guilt, with different holidays.” — Cathy Ladman
delphinis
User
Beiträge: 13
Registriert: Sonntag 5. Juli 2020, 07:34

Ok, ich glaub ich hab's mittlerweile auch kapiert. Ein richtig initialisiertes Hauptfenster das auch seine Referenz mit gibt (zwecks z.B. eines hinzufügens eines Buttons) sollte dann wohl etwa so aussehen:

Code: Alles auswählen

import tkinter as tk
from tkinter import Tk, RIGHT, BOTH, RAISED, YES
from tkinter.ttk import Frame, Button, Style

class Window(Frame):
     
    def __init__(self, master):
        Frame.__init__(self,master)
        self.master.title("Program name")
        self.master.geometry('300x150+-7+0')
        self.style = Style()
        self.style.theme_use("default")

root = tk.Tk()
app = Window(root)
app.pack(fill=BOTH, expand=YES)
root.mainloop()
Antworten