Tkinter verwaltet meine Event-Loops neben meinem mainloop

Ich lerne langsam Tkinter und objektorientierte Programmierung, aber ich habe mich in eine Ecke mit diesem programmiert. Bitte verzeihen Sie meinen Mangel an kritischem Denken auf diesem einen, aber ich habe jeden gefragt, den ich kenne, weiß Python besser als ich und wir können hier nicht zu einer funktionierenden Lösung kommen.

Ich habe eine gui app im arbeiten an, die dazu bestimmt ist, dem Benutzer zu erlauben, Aktiensymbole einzugeben, neue Etiketten für jedes Symbol zu erstellen und jedes Etikett regelmäßig zu aktualisieren. (Irgendwie wie eine wirklich einfache etrade app oder so). Ich habe festgestellt, dass es wirklich einfach ist, dies ohne Gui zu tun, weil ich nur sagen kann:

while True: sPrice = get_stock_price(s) print sPrice 

Aber ich habe meine get_stock_price (s) Funktion auf eine Schaltfläche gebunden, die einen Sub-Frame und ein Label in ihm enthält. Das Problem, das ich konfrontiert habe, ist das Label wird nicht aktualisiert. Ein Freund empfahl, eine andere Methode nur hinzuzufügen, um das Etikett zu aktualisieren, aber die einzige Art, wie ich weiß, wie man es ständig aktualisiert, ist ein

 while True: # get new price # update the label # time.sleep(~1 minute?) 

Dies führt dazu, dass mein Gui-Fenster einfriert und für immer dreht. Ich habe auf allen anderen Threads, die mit dieser Situation zusammenhängen, gelesen, und ich habe viele verschiedene Ratschläge gesehen Rufen Sie nicht in Ihrem Haupt-Thread, verwenden Sie nicht root.update, verwenden Sie Ereignisse, rufen Sie root.something.after (500, Funktion) und ich habe versucht zu implementieren. Was ich noch übrig habe, ist ein Frankenstein von Code, der immer noch meine Aktienwerte abholt, aber sie nicht aktualisieren wird, und ein paar Methoden, die ich nicht kenne, wie man es aktualisiert oder wo ich meinen Code anrufe.

Was ich hoffe, ist eine (potenziell lange, ich weiß, tut mir leid!) Erklärung, was ich falsch mache, und Anregungen, wie man es beheben kann. Ich bin wirklich auf der Suche zu verstehen und beheben das Problem selbst, aber Code-Lösungen wäre genial, solange sie erklärt werden.

Vielen Dank im Voraus !!!

PS: Hier ist mein Code so weit:

 from Tkinter import * import urllib import re import time class MyApp(object): def __init__(self, parent): self.myParent = parent self.myContainer1 = Frame(parent) self.myContainer1.pack() self.createWidgets() button1 = Button(self.myContainer1, command = self.addStockToTrack) self.myContainer1.bind("<Return>", self.addStockToTrack) button1.configure(text = "Add Symbol") button1.pack() def createWidgets(self): # title name root.title("Stock App") # creates a frame inside myContainer1 self.widgetFrame = Frame(self.myContainer1) self.widgetFrame.pack() # User enters stock symbol here: self.symbol = Entry(self.widgetFrame) self.symbol.pack() self.symbol.focus_set() def addStockToTrack(self): s = self.symbol.get() labelName = str(s) + "Label" self.symbol.delete(0, END) stockPrice = get_quote(s) self.labelName = Label(self.myContainer1, text = s.upper() + ": " + str(stockPrice)) self.labelName.pack() self.myContainer1.after(500, self.get_quote) def updateStock(self): while True: labelName = str(s) + "Label" stockPrice = get_quote(s) self.labelName = Label(self.myContainer1, text = s.upper() + ": " + str(stockPrice)) self.labelName.pack() time.sleep(10) def get_quote(symbol): base_url = 'http://finance.google.com/finance?q=' content = urllib.urlopen(base_url + symbol).read() m = re.search('id="ref_\d*_l".*?>(.*?)<', content) if m: quote = m.group(1) else: quote = 'Not found: ' + symbol return quote root = Tk() myapp = MyApp(root) root.mainloop() 

2 Solutions collect form web for “Tkinter verwaltet meine Event-Loops neben meinem mainloop”

Du hast schon eine unendliche Schleife, also solltest du nicht versuchen, einen anderen hinzuzufügen. Stattdessen kannst du die Nachmethode verwenden, um zu bewirken, dass eine Funktion immer wieder so oft aufgerufen wird. In deinem Fall kannst du das ersetzen:

 def updateStock(self): while True: labelName = str(s) + "Label" stockPrice = get_quote(s) self.labelName = Label(self.myContainer1, text = s.upper() + ": " + str(stockPrice)) self.labelName.pack() time.sleep(10) 

… mit diesem:

 def updateStock(self): labelName = str(s) + "Label" stockPrice = get_quote() self.labelName = Label(self.myContainer1, text = s.upper() + ": " + str(stockPrice)) self.labelName.pack() self.after(10000, self.updateStock) 

Das wird ein Zitat bekommen, ein Label hinzufügen, dann in 10 Sekunden (10.000 ms) wieder anrufen lassen.

Allerdings bezweifle ich, dass du alle 10 Sekunden ein neues Label erstellen möchtest? Schließlich füllt sich das Fenster mit Etiketten. Stattdessen kannst du ein Label einmal erstellen und dann das Label in jeder Iteration aktualisieren. Zum Beispiel, schaffen self.label einmal in der init, dann in der Schleife können Sie tun:

 self.labelName.configure(text=s.upper() + ": " + str(stockPrice)) 

Du suchst nach Threading. Setzen Sie das Ereignis, das Sie in einem anderen Thread laufen möchten. Siehe dieses Beispiel:

 import thread, time def myfunc(a1,a2): while True: print a1,a2 time.sleep(1) thread.start_new_thread(myfunc,("test","arg2") tkroot.mainloop() 

Jetzt hast du eine Funktion, die zusammen mit dem Tkinter-Fenster läuft, das die Args jede Sekunde druckt.

EDIT: Ich weiß nicht, warum so viele Stimmen abstimmen. Tkinter funktioniert gut mit Fäden, ich habe diesen Trick schon mehrmals ohne Probleme benutzt. Siehe dieses Beispiel:

Laden Sie eine 10 MB Datei herunter und protokollieren Sie den Fortschritt in ein Tkinter Fenster.

Ohne Gewinde:

 import urllib2,thread import Tkinter as tk class Example(tk.Frame): def __init__(self, parent): tk.Frame.__init__(self, parent) self.parent = parent self.initUI() def initUI(self): self.pack(fill=tk.BOTH, expand=1) canvas = tk.Canvas(self) self.text = canvas.create_text(18,18,anchor=tk.W,font="Purisa",text="Status: Press start to download...") but=tk.Button(text="Start",command=self.start) canvas.create_window((270,18),window=but) canvas.pack(fill=tk.BOTH, expand=1) self.canvas=canvas def start(self): #thread.start_new_thread( self.download("http://ipv4.download.thinkbroadband.com/10MB.zip","10mb.zip") #) def onEnd(self): self.canvas.itemconfig(self.text, text="Status: done!") def download(self,url,file_name): u = urllib2.urlopen(url) f = open(file_name, 'wb') meta = u.info() file_size = int(meta.getheaders("Content-Length")[0]) print "Downloading: %s Bytes: %s" % (file_name, file_size) file_size_dl = 0 block_sz = 1024*50 #50 kb while True: buffer = u.read(block_sz) if not buffer: break file_size_dl += len(buffer) f.write(buffer) status = r"[%3.2f%%]" % (file_size_dl * 100. / file_size) self.canvas.itemconfig(self.text,text="Status: downloading..."+status) f.close() self.onEnd() def main(): root = tk.Tk() root.resizable(0,0) ex = Example(root) root.geometry("300x70") root.mainloop() main() 

Das Fenster friert, bis der Download fertig ist.

Mit Gewinde:

 import urllib2,thread import Tkinter as tk class Example(tk.Frame): def __init__(self, parent): tk.Frame.__init__(self, parent) self.parent = parent self.initUI() def initUI(self): self.pack(fill=tk.BOTH, expand=1) canvas = tk.Canvas(self) self.text = canvas.create_text(18,18,anchor=tk.W,font="Purisa",text="Status: Press start to download...") but=tk.Button(text="Start",command=self.start) canvas.create_window((270,18),window=but) canvas.pack(fill=tk.BOTH, expand=1) self.canvas=canvas def start(self): thread.start_new_thread( self.download("http://ipv4.download.thinkbroadband.com/10MB.zip","10mb.zip") ) def onEnd(self): self.canvas.itemconfig(self.text, text="Status: done!") def download(self,url,file_name): u = urllib2.urlopen(url) f = open(file_name, 'wb') meta = u.info() file_size = int(meta.getheaders("Content-Length")[0]) print "Downloading: %s Bytes: %s" % (file_name, file_size) file_size_dl = 0 block_sz = 1024*50 #50 kb while True: buffer = u.read(block_sz) if not buffer: break file_size_dl += len(buffer) f.write(buffer) status = r"[%3.2f%%]" % (file_size_dl * 100. / file_size) self.canvas.itemconfig(self.text,text="Status: downloading..."+status) f.close() self.onEnd() def main(): root = tk.Tk() root.resizable(0,0) ex = Example(root) root.geometry("300x70") root.mainloop() main() 

Friert nicht ein und der Text wird normal aktualisiert.

  • Python qt, Display Text / Label über ein anderes Widget (Phonon)
  • Wie ändere ich Farben von mehreren Widgets nach dem Schweben in Tkinter?
  • Ipywidgets: Aktualisieren Sie ein Widget basierend auf Ergebnissen von einem anderen
  • WxPython: Kann ein wx.PyControl einen wx.Sizer enthalten?
  • Kivy: Wie bekomme ich das Widget von id (ohne kv)
  • Wie man einen tkinter Eintrag Standardwert dauerhaft macht
  • Tkinter - Protokollierung von Text in Text Widget
  • Mit matplotlib Slider-Widget, um den Clim im Bild zu ändern
  • Größe eines Widgets in einem anderen Widget in Tkinter
  • Ausgabe mit 'StringVar' im Python-Programm
  • Unterklassen von Tkinter, um ein benutzerdefiniertes Widget zu erstellen
  • Python ist die beste Programmiersprache der Welt.