【发布时间】:2014-08-17 16:59:49
【问题描述】:
中年父亲(电气工程师不是专业程序员)试图教我 13 岁的女儿电子和编程。到目前为止,我喜欢 Python。我正在构建一个程序,用 tkinter GUI 和 DS18B20 传感器显示我们房子的温度。
我们通过阅读书籍、在线研究和使用 Stack Overflow 解决错误(这个网站太棒了!)拼凑出以下程序。
现在我们很困惑,我们不断收到间歇性错误,当我们在 Raspberry 上加载空闲后第一次运行程序时,它运行正常。
第二次以及之后的所有时间,我们都会收到以下错误消息:
Traceback (most recent call last):
File "/home/pi/Code-working-library/stackoverflow-paste.py", line 140, in <module>
app.equipTemp.set(tempread)
File "/usr/lib/python2.7/lib-tk/Tkinter.py", line 203, in set
return self._tk.globalsetvar(self._name, value)
RuntimeError: main thread is not in main loop
注意,我们的理解是,为了有一个静态窗口和更新标签,更新的温度从我们的传感器 (DS18B20) 中读取,我们需要使用一个线程。我们开始的示例代码有 _init_ 语句,前后只有一个下划线 - 不知道为什么,如果我添加第二个下划线,我会收到错误消息。我们作为基础的更新窗口代码来自Raspberry Pi forum
这是我们的代码:
from Tkinter import *
import tkFont
import os
import glob
import time
import subprocess
import re
import sys
import time
import threading
import Image
import ImageTk
os.system('modprobe w1-gpio')
os.system('modprobe w1-therm')
#28-000005c6ba08
sensors = ['28-000005c6ba08']
sensors1 = ['28-000005c70f69']
def read_temp_raw():
catdata = subprocess.Popen(['cat',device_file], stdout=subprocess.PIPE, stderr=subprocess.PIPE)
out,err = catdata.communicate()
out_decode = out.decode('utf-8')
lines = out_decode.split('\n')
return lines
def read_temp():
lines = read_temp_raw()
while lines[0].strip()[-3:] != 'YES':
time.sleep(0.2)
lines = read_temp_raw()
equals_pos = lines[1].find('t=')
if equals_pos != -1:
temp_string = lines[1][equals_pos+2:]
temp_c = float(temp_string) / 1000.0
temp_f = temp_c * 9.0 / 5.0 + 32.0
return temp_f
########### build window ###################
bground="grey"
class App(threading.Thread):
def _init_(self):
threading.Thread._init_(self)
self.start()
def callback(self):
self.root.quit()
def run(self):
#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"
self.root.mainloop() #start monitoring and updating the GUI
########### Start Loop ###################
print "starting app"
app = App()
app.start()
print "app started"
################### Begin ds18b20 function ##############
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)
app.equipTemp.set(tempread)
time.sleep(5)
##################### END ds18b20 Function ######
【问题讨论】:
-
对 tkinter 做的不多,但 gui 工具包通常只在主线程上运行。显而易见的解决方案:将主循环留在主线程上,然后将计算放到另一个线程中!
-
是的,将您的计算放在 App 类中。
-
感谢您的快速响应,但请把我当作白痴对待。当您说将我的计算放在应用程序类中时,您是指注释后的代码:## Begin ds18b20 function ## 还是代码开头的两个 read temp 函数?
-
现在你在主线程中进行计算(Begin ds18b20 函数之后的东西),你的 gui 在一个额外的线程中。你应该反过来做!
-
顺便说一句,您绝对应该使用
__init__,而不是_init_。您在使用__init__时遇到的任何错误可能是因为您犯了一个合法的编码错误,该错误仅在实际调用__init__时发生。
标签: python multithreading raspberry-pi