python - 几秒钟后程序出现故障(tkinter)
问题描述
我正在编写一个程序,它应该显示一些通过 CanBus 的数据(数据每 200 毫秒刷新一次),但是当我像这样从我的类中创建一个对象时:
batteryDegree = PlaceInfo(root,img='battery.png',fotox=0.23,fotoy=0.35,foto_y_resize=180,foto_x_resize=180,anchor='center', text="100*C",textx=0.23,texty=0.38,canid=0x1000400,byte=2,size=30)
motorDegree = PlaceInfo(root,img='motor.png',fotox=0.75,fotoy=0.35,foto_y_resize=200,foto_x_resize=200,anchor='center', text="100*C",textx=0.76,texty=0.37,canid=0x1000400,byte=0,size=30)
这是我的课:
bus = can.interface.Bus(channel='can0')
root = Tk()
root.geometry("800x480")
root.config(bg='red')
canvas = Canvas(root,width=800,height=480,highlightthickness=0)
canvas.pack()
class PlaceInfo():
def __init__(self,root, **kwargs):
self.root = root
if 'img' in kwargs:
if 'foto_x_resize' in kwargs and 'foto_y_resize' in kwargs:
self.png = ImageTk.PhotoImage(Image.open('imgs/' + kwargs['img']).resize((kwargs['foto_x_resize'],kwargs['foto_y_resize']),Image.ANTIALIAS))
else:
self.png = ImageTk.PhotoImage(Image.open('imgs/' + kwargs['img']))
self.image = canvas.create_image(800 * kwargs['fotox'],480 * kwargs['fotoy'] ,image=self.png,anchor='center')
if 'text' in kwargs:
self.text = canvas.create_text(kwargs['textx'] * 800,
kwargs['texty'] * 480,
text=kwargs['text'],
fil=kwargs['kleur'] if 'kleur' in kwargs else 'white',
font=('arial',kwargs['size'] if 'size' in kwargs else 10))
if 'canid' in kwargs and 'index' not in kwargs:
self.changeData(kwargs['canid'], kwargs['byte'],kwargs['textx'], kwargs['texty'],kwargs['size'])
elif 'canid' in kwargs and 'index' in kwargs:
self.changeDataWithIndex(kwargs['canid'], kwargs['byte'],kwargs['textx'], kwargs['texty'],kwargs['size'],kwargs['index'])
def changeData(self,canid,byte,textx,texty,size):
try:
msg = bus.recv(1)
canvas.delete(self.text)
if msg.arbitration_id == canid:
self.data = msg.data[byte]
self.text = canvas.create_text(textx * 800,
texty * 480,
text=str(self.data),
fill='white',
font=('arial',size))
except Exception as e:
print(e)
self.root.after(250,lambda: self.changeData(canid,byte,textx,texty,size))
该程序运行了几秒钟,但之后中断,我的意思是它只是停止显示数据,当我移动窗口时,颜色到处都是。(当我在我的函数中打印某些东西时,它仍然会打印)
解决方案
由于您有多个实例PlaceInfo
,因此在读取 CanBus 的任务后有多个实例,这可能会导致竞争条件。同样在任务 A 之后可以读取任务 B 的消息,反之亦然。
您需要集中读取 CanBus 并在线程中执行读取,因为这recv()
是一个阻塞任务。
因此,您可以创建一个CanReader
扩展threading.Thread
并调用recv()
其run()
函数的类:
from threading import Thread
from queue import SimpleQueue
class CanReader(Thread):
def __init__(self, channel):
super().__init__(daemon=True)
self._bus = can.interface.Bus(channel=channel)
self._queues = {}
def register(self, canid):
if canid not in self._queues:
self._queues[canid] = []
queue = SimpleQueue()
self._queues[canid].append(queue)
return queue
def run(self):
while True:
msg = self._bus.recv()
for q in self._queues[msg.arbitration_id]:
q.put(msg)
然后你可以创建一个CanReader
如下的实例:
bus = CanReader('can0')
bus.start()
CanReader
提供了一个函数register()
来PlaceInfo
注册和获取一个对象,该SimpleQueue
对象保存CanReader
.
以下为修改PlaceInfo
:
class PlaceInfo():
def __init__(self, root, **kwargs):
self.root = root
img = kwargs.get('img', None)
if img:
image = Image.open('images/'+img)
foto_x_resize, foto_y_resize = kwargs.get('foto_x_resize'), kwargs.get('foto_y_resize')
if foto_x_resize and foto_y_resize:
image = image.resize((foto_x_resize, foto_y_resize), Image.ANTIALIAS)
self.png = ImageTk.PhotoImage(image)
self.image = canvas.create_image(800*kwargs['fotox'], 480*kwargs['fotoy'], image=self.png, anchor='center')
textx = kwargs.get('textx', None)
texty = kwargs.get('texty', None)
fill = kwargs.get('kleur', 'white')
size = kwargs.get('size', 10)
text = kwargs.get('text', None)
if text:
self.text = canvas.create_text(textx*800, texty*480, text=text, fill=fill, font=('arial',size))
canid = kwargs.get('canid', None)
if canid:
self.queue = bus.register(canid) # register to CanReader using canid
if 'index' not in kwargs:
self.changeData(canid, kwargs['byte'])
else:
self.changeDataWithIndex(canid, kwargs['byte'], kwargs['index'])
def changeData(self, canid, byte):
try:
msg = self.queue.get_nowait() # read message
self.data = msg.data[byte]
canvas.itemconfigure(self.text, text=str(self.data))
except Exception as e:
print(e)
self.root.after(250, self.changeData, canid, byte)
希望这可以帮助您解决问题。
推荐阅读
- php - Codeigniter:登录时使用验证码始终存储验证码图像
- java - 如何编写客户端以从 Rest webservice 获取数据和图像文件
- c# - 将值绑定到 DataTemplate 内的 UserControl 的 DependencyProperty 会返回 UserControl 本身而不是值
- python - MATLAB 的 sgolay(k, f) 的 Python 等价物是什么?
- javascript - Html5 日期字段无法设置回来自后端的日期字段
- java - 以特定模式或特定字符替换字符
- android - 从 Android 应用程序向 Whatsapp 上的特定联系人发送消息
- python-3.x - Python,tkinter 如何防止在主窗口调整大小期间隐藏/调整小部件
- python - 如何创建元组其中输入是列中的文本并输出为行号?
- jxls - JXLS 不可访问或未知属性