2016-05-14 17 views
2

Hallo Ich habe eine kleine Python-GUI-Schnittstelle mit zwei Tasten, starten (das startet einen Zähler) und zu stoppen (das heißt, um den Zähler zu stoppen), der Zähler ist eine Endlosschleife, da ich nicht möchte, dass sie endet, wenn nicht die zweite Schaltfläche geklickt wird. Das Problem ist, dass die zweite Taste nicht angeklickt werden kann, während die Funktion von der ersten noch läuft. Ich lese, dass ich Threading verwenden muss und ich habe versucht, aber ich verstehe nicht vollständig, wie ich das tun kann. Bitte helfen Sie.Python, Tkinter: Wie kann ich verhindern, tkinter GUI Mainloop Absturz mit Threading

from Tkinter import * 
import threading 


class Threader(threading.Thread): 
    def run(self): 
     for _ in range(10): 
      print threading.current_thread().getName() 

    def main(self): 
     import itertools 
     for i in itertools.count(1, 1): 
      print i 

    def other(self): 
     print "Other" 

m = Threader(name="main") 
o = Threader(name="other") 

try: 
    '''From here on we are building the Gui''' 
    root = Tk() 

    '''Lets build the GUI''' 
    '''We need two frames to help sort shit, a left and a right vertical frame''' 
    leftFrame = Frame(root) 
    leftFrame.pack(side=LEFT) 
    rightFrame = Frame(root) 
    rightFrame.pack(side=RIGHT) 
    '''Widgets''' 
    '''Buttons''' 
    playButton = Button(leftFrame, text="Play", fg="blue", command=m.main) 
    stopButton = Button(rightFrame, text="Stop", fg="red", command=o.other) 
    playButton.pack(side=TOP) 
    stopButton.pack(side=BOTTOM) 

    root.mainloop() 
except Exception, e: 
    print e 

Antwort

3

Hier ist ein kurzes Beispiel für die Verwendung threading. Ich nahm Ihre other Funktion heraus und ich weiß nicht, warum Sie itertools hier verwenden. Ich nahm das auch heraus und rüstete einfach mit einem einfachen Threading-Beispiel auf.

Ein paar Dinge:

Sie Setup threading.Thread als Basisklasse für Threader verwenden, aber man kann nie wirklich initialisiert die Basisklasse.

Wenn Sie Threading verwenden, möchten Sie in der Regel eine run Methode definieren und dann start() verwenden, um den Thread zu starten. Rufen Sie start() wird run aufrufen.

Sie müssen Threading verwenden, um zu verhindern, dass Ihre GUI blockiert, weil tkinter nur ein Thread in einer riesigen Schleife ist. Wann immer Sie einen lang andauernden Prozess haben, blockiert er diesen Thread, bis der aktuelle Prozess abgeschlossen ist. Deshalb ist es in einen anderen Thread eingefügt. Python hat etwas namens GIL, das verhindert true Parallelisierung (ich habe dieses Wort erfunden), da es immer nur ein Thread auf einmal verwendet werden kann. Stattdessen verwendet es Zeit-Slicing, die GIL-Art von "fragt" zwischen ihnen, um die Erscheinung von mehreren gleichzeitig ausgeführten Aufgaben zu geben. Für echte Parallelverarbeitung sollten Sie multiprocessing verwenden.

Im folgenden Code habe ich self.daemon = True verwendet. den Faden einstellen, um es ein Dämon töten, wenn Sie das Hauptprogramm beenden (In diesem Fall wird die Tk GUI)

from tkinter import * 
import threading, time 

class Threader(threading.Thread): 

    def __init__(self, *args, **kwargs): 

     threading.Thread.__init__(self, *args, **kwargs) 
     self.daemon = True 
     self.start() 

    def run(self): 

     while True: 
      print("Look a while true loop that doesn't block the GUI!") 
      print("Current Thread: %s" % self.name) 
      time.sleep(1) 

if __name__ == '__main__': 

    root = Tk() 
    leftFrame = Frame(root) 
    leftFrame.pack(side=LEFT) 
    rightFrame = Frame(root) 
    rightFrame.pack(side=RIGHT) 
    playButton = Button(leftFrame, text="Play", fg="blue", 
     command= lambda: Threader(name='Play-Thread')) 
    stopButton = Button(rightFrame, text="Stop", fg="red", 
     command= lambda: Threader(name='Stop-Thread')) 
    playButton.pack(side=TOP) 
    stopButton.pack(side=BOTTOM) 
    root.mainloop() 
0

Für etwas so einfach wie ein Zähler, Tkinter ist nach() Methode ist in der Regel die bessere Wahl. Sie können eine Instanzvariable verwenden, um sie ein- und auszuschalten.

class TimerTest(): 
    def __init__(self, root): 
     self.root=root 

     Button(root, text="Play", fg="blue", 
          command=self.startit).grid(row=1, column=0) 
     Button(root, text="Stop", fg="red", 
          command=self.stopit).grid(row=1, column=1) 

     self.is_running=True 
     self.count=IntVar() 
     Label(root, textvariable=self.count, 
       bg="lightblue").grid(row=0, column=0, columnspan=2, sticky="ew") 

    def startit(self): 
     self.is_running=True 
     self.increment_counter() 

    def increment_counter(self): 
     if self.is_running: 
      c=self.count.get() 
      c += 1 
      self.count.set(c) 
      root.after(1000, self.increment_counter) ## every second 

    def stopit(self): 
     self.is_running = False 

root = Tk() 
TT=TimerTest(root) 
root.mainloop()