Him*_*sal 1 python linux tkinter python-multithreading
我在windows中编写了这段代码,但是当我将它复制到我的raspberry pi(运行Jessie Debian)时,它会给出运行时错误
我的代码:
from Tkinter import *
from PIL import ImageTk,Image
from time import sleep
import thread
root = Tk()
img=ImageTk.PhotoImage(Image.open("1.jpg").resize((root.winfo_screenwidth()-3,root.winfo_screenheight()-3)))
panel = Label(root, image = img)
panel.pack(side = "bottom", fill = "both", expand = "yes")
if __name__ == '__main__':
thread.start_new_thread(root.mainloop,())
for i in xrange(1,5):
sleep(1)
img2 = ImageTk.PhotoImage(Image.open(str(i)+".jpg").resize((root.winfo_screenwidth()-3,root.winfo_screenheight()-3)))
panel.configure(image = img2)
panel.image = img2
Run Code Online (Sandbox Code Playgroud)
在linux中执行时会出错:
Unhandled exception in thread started by <bound method Tk.mainloop of <Tkinter.Tk instance at 0x75b605d0>>
Traceback (most recent call last):
File "/usr/lib/python2.7/lib-tk/Tkinter.py", line 1124, in mainloop
self.tk.mainloop(n)
RuntimeError: Calling Tcl from different appartment
Run Code Online (Sandbox Code Playgroud)
我该怎么做才能在两个平台上运行此代码
无法从不同的线程调用Tcl函数.它在Windows上运行的事实可能是因为检查此条件是错误的.
你需要做的是有一个与之交谈的"UI线程" Tk.通常,所有这个线程明确地做的是:
root.mainloop()如果您希望稍后对UI进行更改,则应在事件处理程序中执行此操作.如果要执行某些代码以响应非UI事件,可以root使用在主循环上执行或调度函数来注册自定义事件处理程序after.
from Tkinter import *
from PIL import ImageTk, Image
root = Tk()
panel = Label(root)
panel.pack(side = "bottom", fill = "both", expand = "yes")
def showImage(i):
img = ImageTk.PhotoImage(Image.open(str(i)+".jpg"))
img = img.resize((root.winfo_screenwidth()-3, root.winfo_screenheight()-3))
panel.configure(image = img)
panel.image = img
class Task(object):
# A little helper to wrap a function with arguments.
def __init__(self, fun, *args, **kwargs):
self.fun = fun
self.args = args
self.kwargs = kwargs
def __call__(self):
self.fun(*self.args, **self.kwargs)
if __name__ == '__main__':
for i in range(1, 5):
# run showImage(i) on the mainloop after (i - 1) seconds
root.after((i - 1) * 1000, Task(showImage, i))
root.mainloop()
Run Code Online (Sandbox Code Playgroud)
如果需要,您可以从另一个线程安排函数:
import thread
def doStuff():
for i in range(1, 5):
sleep(1)
root.after(0, Task(showImage, i))
thread.start_new_thread(doStuff, ())
Run Code Online (Sandbox Code Playgroud)
注意:我创建的Task目的很容易指定我想showImage用给定的运行i.通常,functools.partial会很好,但显然Tkinter由于动态创建方法和装饰器它不能很好地运行,得到错误'functools.partial'对象没有属性'__module__'
你也可以这样做:
(lambda ii: lambda: showImage(ii))(i)
Run Code Online (Sandbox Code Playgroud)
但是,当您稍后返回代码时,这可能会让您感到困惑.
如果您没有预料到有其他任务,您可以这样做:
def showImage(i):
def newfun():
img = ImageTk.PhotoImage(Image.open(str(i)+".jpg"))
img = img.resize((root.winfo_screenwidth()-3, root.winfo_screenheight()-3))
panel.configure(image = img)
panel.image = img
return newfun
Run Code Online (Sandbox Code Playgroud)