<p>你需要在主线程中运行GUI代码,你的温度读取代码需要在后台线程中。更新主线程中的GUI是安全的,因此您可以通过<code>Queue</code>将从后台线程读取的温度数据传递回主线程,并让主线程使用<code>self.root.after()</code>定期检查队列中的数据:</p>
<pre><code>from Tkinter import *
import tkFont
import os
import glob
import time
import threading
import Image
import Queue
def update_temp(queue):
""" Read the temp data. This runs in a background thread. """
while True:
# 28-000005c6ba08
i = "28-000005c6ba08"
base_dir = '/sys/bus/w1/devices/'
device_folder = glob.glob(base_dir + i)[0]
device_file = device_folder + '/w1_slave'
tempread=round(read_temp(),1)
# Pass the temp back to the main thread.
queue.put(tempread)
time.sleep(5)
class Gui(object):
def __init__(self, queue):
self.queue = queue
#Make the window
self.root = Tk()
self.root.wm_title("Home Management System")
self.root.minsize(1440,1000)
self.equipTemp = StringVar()
self.equipTemp1 = StringVar()
self.equipTemp2 = StringVar()
self.customFont = tkFont.Font(family="Helvetica", size=16)
# 1st floor Image
img = Image.open("HOUSE-PLANS-01.png")
photo = ImageTk.PhotoImage(img)
Label1=Label(self.root, image=photo)
Label1.place(x=100, y=100)
# 2nd floor
img2 = Image.open("HOUSE-PLANS-02.png")
photo2 = ImageTk.PhotoImage(img2)
Label1=Label(self.root, image=photo2)
Label1.place(x=600, y=100)
# Basement image
img3 = Image.open("HOUSE-PLANS-03.png")
photo3 = ImageTk.PhotoImage(img3)
Label1=Label(self.root, image=photo3)
Label1.place(x=100, y=500)
# Attic Image
img4 = Image.open("HOUSE-PLANS-04.png")
photo4 = ImageTk.PhotoImage(img4)
Label1=Label(self.root, image=photo4)
Label1.place(x=600, y=500)
# House Isometric Image
img5 = Image.open("house-iso.png")
photo5 = ImageTk.PhotoImage(img5)
Label1=Label(self.root, image=photo5)
Label1.place(x=1080, y=130)
#Garage Temp Label
Label2=Label(self.root, textvariable=self.equipTemp, width=6, justify=RIGHT, font=self.customFont)
Label2.place(x=315, y=265)
print "start monitoring and updating the GUI"
# Schedule read_queue to run in the main thread in one second.
self.root.after(1000, self.read_queue)
def read_queue(self):
""" Check for updated temp data"""
try:
temp = self.queue.get_nowait()
self.equipTemp.set(temp)
except Queue.Empty:
# It's ok if there's no data to read.
# We'll just check again later.
pass
# Schedule read_queue again in one second.
self.root.after(1000, self.read_queue)
if __name__ == "__main__":
queue = Queue.Queue()
# Start background thread to get temp data
t = threading.Thread(target=update_temp, args=(queue,))
t.start()
print "starting app"
# Build GUI object
gui = Gui(queue)
# Start mainloop
gui.root.mainloop()
</code></pre>
<p><strong>编辑:</strong></p>
<p>在实际查看了tkinter源代码以及Python bug tracker之后,似乎与其他几乎所有GUI库不同,只要在应用程序的主线程中运行mainloop,tkinter<em>就可以实现线程安全。有关更多信息,请参阅我添加的答案<a href="https://stackoverflow.com/a/25352087/2073595">here</a>,或者直接转到Python bug tracker<a href="http://bugs.python.org/issue11077" rel="nofollow noreferrer">here</a>上关于tkinter线程安全的已解决问题。如果tkinter源代码和Python的bug跟踪器是正确的,那就意味着只要在主线程中运行主循环,就可以很高兴地直接从温度读取线程调用<code>gui.equipTemp.set()</code>-不需要<code>Queue</code>。在我的测试中,效果确实不错。</p>