Tkinter 在我的主循环旁边管理我的事件循环
问题描述
我一直在慢慢学习 Tkinter 和面向对象的编程,但我已经把自己编程到了这个角落.请原谅我在这方面缺乏批判性思维,但我已经问过我认识的每个人,谁比我更了解 Python,我们无法在这里找到可行的解决方案.
I've been slowly learning Tkinter and object-oriented programming but I've programmed myself into a corner with this one. please forgive my lack of critical thinking on this one, but i've asked everyone I know who knows python better than me and we can't get to a working solution here.
我正在开发一个 gui 应用程序,它允许用户输入股票代码,为每个代码创建新标签,然后定期更新每个标签.(有点像一个非常基本的 etrade 应用程序或其他东西).我发现没有 gui 也很容易做到这一点,因为我可以说:
I've got a gui app im working on that is meant to allow the user to input stock symbols, create new labels for each symbol, and then update each label periodically. (kinda like a really basic etrade app or something). I've found it's really easy to do this without a gui because I can just say:
while True:
sPrice = get_stock_price(s)
print sPrice
但我已将我的 get_stock_price(s) 函数绑定到一个按钮,该按钮会生成一个子框架和一个包含在其中的标签.我面临的问题是标签不会更新.一位朋友建议添加另一种方法来更新标签,但是我知道如何持续更新它的唯一方法是做一个
but i've bound my get_stock_price(s) function to a button, which spawns a sub-frame and a label contained inside it. The problem i've faced is the label will not update. A friend recommended to add another method solely to update the label, however the only way I know how to continuously update it is do a
while True:
# get new price
# update the label
# time.sleep(~1 minute?)
这会导致我的 gui 窗口永远冻结和旋转.我一直在阅读与这种特殊情况相关的所有其他线程,并且看到了许多不同的建议;不要在主线程中调用睡眠,不要使用 root.update,使用事件,调用 root.something.after(500, function) 并且我已经尝试实现.我留下的是一段代码,它仍然会检索我的股票值,但不会更新它们,还有一些我不知道如何更新或在哪里调用我的代码的方法.
this causes my gui window to freeze and spin forever. I've been reading up on all the other threads related to this particular situation, and I've seen many different advices; don't call sleep in your main thread, don't use root.update, use events, call root.something.after(500, function) and i've tried to implement. What i've been left with is a frankenstein of code that will still retrieve my stock values, but wont update them, and a few methods that I don't know how to update, or where to call in my code.
我希望的是(可能很长,我知道.对不起!)解释我做错了什么,以及如何解决它的建议.我真的很想自己理解和解决这个问题,但是只要对代码解决方案进行解释,它们就会很棒.
What im hoping for is a (potentially long, I know. Sorry!) explanation of what i'm doing wrong, and suggestions on how to fix it. I'm really looking to understand and fix the issue myself, but code-solutions would be awesome so long as they are explained.
提前非常感谢!!!
PS:到目前为止,这是我的代码:
PS: Here is my code so far:
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()
解决方案
你已经有一个无限循环在运行,所以你不应该尝试添加另一个.相反,您可以使用 after
方法使函数每隔一段时间重复调用一次.在您的情况下,您可以替换它:
You already have an infinite loop running, so you shouldn't be trying to add another one. Instead, you can use the after
method to cause a function to be repeatedly called every so often. In your case, you can replace this:
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 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)
这将获得一个报价,添加一个标签,然后安排自己在 10 秒(10,000 毫秒)内再次被调用.
This will get a quote, add a label, then arrange for itself to be called again in 10 seconds (10,000 ms).
但是,我怀疑您是否想每 10 秒创建一个新标签,对吗?最终窗口将填满标签.相反,您可以创建一次标签,然后在每次迭代中更新标签.例如,在 init 中创建一次 self.label
,然后在循环中你可以这样做:
However, I doubt that you want to create a new label every 10 seconds, do you? Eventually the window will fill up with labels. Instead, you can create a label once, then update the label in each iteration. For example, create self.label
once in the init, then in the loop you can do:
self.labelName.configure(text=s.upper() + ": " + str(stockPrice))
相关文章