Threads notwendig?

Fragen zu Tkinter.
Antworten
Graf_Dracula
User
Beiträge: 20
Registriert: Donnerstag 17. Februar 2011, 16:05

Ich habe in meiner GUI mehrere Button, hinter denen je eine Funktion liegt.
Jetzt hätte ich gern hinter einem Button eine "Anhalten"-Funktion gelegt, die eine laufende andere Funktion unterbrechen kann.

Wenn ich in meinem Beispielcode auf Start drücke, addiert er ja sinnloserweise in der for-Schleife. Während dieser zeit ist aber die Start-Taste in der GUI gedrückt und ich kann meine Abbrechen-Taste gar nicht drücken (ich weiß ehh noch nicht, ob die implementierte Abbruchlösung so sinnvoll ist). Kann ich die GUI wieder irgendwie aktiv schalten und einen weiteren Button drücken, oder muss ich das Ganze mit Threads lösen? ... und wenn ja, hat da jemand nen Vorschlag?

Code: Alles auswählen

from tkinter import *
globStop = 0
############################################
def main():
    root = Tk()
    mainFrame = Frame(root, borderwidth=2)
    mainFrame.pack(fill='y', padx=10, pady=10 )
    startButton = Button(mainFrame, text="Start", command=start, width=20, height=2)
    startButton.pack(side=LEFT, anchor='w', padx=10, pady=10)
    stopButton = Button(mainFrame, text="Stop", command=abbrechen, width=20, height=2)
    stopButton.pack(side=LEFT, anchor='w', padx=10, pady=10)
    root.mainloop()
############################################
def start():
    global globStop
    a = 0
    for i in range(9990000):
        if globStop: break
        a += i
    globStop = 0
############################################
def abbrechen():
    global globStop
    globStop = 1
############################################
main()
Benutzeravatar
numerix
User
Beiträge: 2696
Registriert: Montag 11. Juni 2007, 15:09

1. Threads sind nicht notwendig.
2. Bevor du weiter mit Tkinter bzw. GUI-Programmierung allgemein arbeitest, solltest du dich mit OOP-Grundlagen vetraut machen und mit eigenen Klassen arbeiten. Dann wirst du auch das "global" los und das solltest du unbedingt loswerden.
3. Das hilft dir beim Schleifenproblem: http://www.python-forum.de/viewtopic.php?f=18&t=25531
Xynon1
User
Beiträge: 1267
Registriert: Mittwoch 15. September 2010, 14:22

Naja, ein Thread wäre nun nicht undenkbar, aber du solltest überlegen was du brauchst. Zum einen könnt man in die Schleife die "update"-Methode für Tkinterwidgets nutzen, ist aber nur empfehlenswert wenn es recht selten aufgerufen wird. Zum anderen könnte man sich was mit der "after"-Methode basteln, welche bis Ausführungszeiten von mehr als 1ms effektiv wäre. Alles was darunter liegt, also schneller ausgeührt werden muss, wirst du wohl um einen Thread nicht herum kommen, hierzu sollte man einfach einen Background-Thread öffnen und die Daten von diesem in eine "Queue" schreiben. Diese kann man dann auf der GUI-Ebene auslesen. Also hier ist darauf zu achten das es keine direkter Interaktition mit der Mainloop der GUI aufgebaut wird da es sonst zu Abstürzen kommen kann.

Hier mal ein Beispiel für die "after"-Methode:

Code: Alles auswählen

import tkinter

class Counter(tkinter.IntVar):

    def __init__(self, master, counts=0):
        tkinter.Variable.__init__(self, master, counts)
        self.running = False
        self.run()

    def run(self):
        if self.running:
            self.set(self.get() - 1)
        self._master.after(500, self.run)

    def start(self):
        self.running = True

    def stop(self):
        self.running = False


def update(widget, variable, delay):
    widget.config(text=str(variable.get()))
    widget.after(delay, update, widget, variable, delay)    

if __name__ == "__main__":
    root = tkinter.Tk()

    counter = Counter(root, 9990000)

    label = tkinter.Label(root)
    label.pack()
    update(label, counter, 500)
    
    start_button = tkinter.Button(root, text="Start", width=20, 
                                  command=counter.start)
    start_button.pack(side="left")
                      
    stop_button = tkinter.Button(root, text="Stop", width=20,
                                 command=counter.stop)
    stop_button.pack(side="left")

    root.mainloop()
Traue keinem Computer, den du nicht aus dem Fenster werfen kannst.
Xynon auf GitHub
Antworten