我有以下脚本基于另一个Stackoverflow问题的解决方案。我有一个带有图片的tkinter GUI,当有一个新图片时应该刷新。
class App(threading.Thread):
def __init__(self):
threading.Thread.__init__(self)
self.start()
def callback(self):
self.root.quit()
def run(self):
self.root = Tk()
self.root.geometry("{0}x{1}+0+0".format(800,800))
files = sorted(os.listdir(os.getcwd()),key=os.path.getmtime)
Label(self.root,image = ImageTk.PhotoImage(Image.open(files[-1]).resize((300, 200)))).grid(row = 1, column = 0)
Label(self.root, text=files[-1]).grid(row=0, column=0)
self.root.mainloop()
def update(self):
files = sorted(os.listdir(os.getcwd()),key=os.path.getmtime)
img1 = self.ImageTk.PhotoImage(self.Image.open(files[-1]).resize((300, 200)))
Label(self.root,image = img1).grid(row = 1, column = 0)
Label(self.root, text=files[-1]).grid(row=0, column=0)
self.root.update()
app = App()
app.update()
我收到此错误:
Traceback (most recent call last):
File "/usr/lib/python3/dist-packages/PIL/ImageTk.py", line 176, in paste
tk.call("PyImagingPhoto", self.__photo, block.id)
_tkinter.TclError: invalid command name "PyImagingPhoto"
During handling of the above exception, another exception occurred:
Traceback (most recent call last):
File "./mainloop.py", line 98, in <module>
app.update()
File "./mainloop.py", line 79, in update
img1 = ImageTk.PhotoImage(Image.open(files[-1]).resize((300, 200)))
File "/usr/lib/python3/dist-packages/PIL/ImageTk.py", line 115, in __init__
self.paste(image)
File "/usr/lib/python3/dist-packages/PIL/ImageTk.py", line 182, in paste
_imagingtk.tkinit(tk.interpaddr(), 1)
OverflowError: Python int too large to convert to C ssize_t
我做错了什么?使用文件名创建标签确实有效。文件名是有效文件。当脚本不在thread.Threading部分内部时脚本可以正常工作。当按下Raspberry GPIO按钮时,我想用最新的图片更新屏幕(脚本将拍摄带有camara的新照片)。所以屏幕应该加载最新拍摄的照片。
答案 0 :(得分:0)
tkinter 不线程安全(默认情况下)。处理GUI的所有操作必须在主线程中完成。您可以使用事件回调来执行您所要求的操作,但除非您实现了一个提供给主循环的事件队列,否则线程可以并且将会破坏tkinter。
此外,堆栈跟踪似乎指向此处的代码 - 堆栈跟踪根本不与显示的代码相交。
此外,调用root.update()通常是一个坏主意 - 它启动另一个本地事件循环,它可能能够为另一个事件循环广告调用另一个root.update()。 root.update_idletasks()比完全root.update()
更安全