Tkinter 代码在 Windows 上运行但不在 Linux 上运行
Tkinter code runs on Windows but not on Linux
我在 windows 中编写了这段代码并且它有效但是当我将它复制到我的 raspberry pi(运行ning Jessie Debian based)时它给出了 运行time 错误
我的代码:
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
在 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
我应该如何处理 运行 两个平台上的这段代码
不能从不同线程调用 Tcl 函数。它适用于 Windows 的事实可能是因为对此条件的检查有误。
您需要做的是拥有一个与 Tk
对话的 "UI thread"。通常,此线程显式执行的所有操作是:
- 设置所有小部件和事件处理程序
- 致电
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()
如果需要,您可以从另一个线程安排函数:
import thread
def doStuff():
for i in range(1, 5):
sleep(1)
root.after(0, Task(showImage, i))
thread.start_new_thread(doStuff, ())
注意:我创建 Task
是为了轻松指定我想要 运行 showImage
和给定的 i
。通常,functools.partial
会很好,但由于 dynamic create method and decorator, got error 'functools.partial' object has no attribute '__module__'
,它显然不能与 Tkinter
一起使用
你也可以这样做:
(lambda ii: lambda: showImage(ii))(i)
但是当您稍后 return 代码时,这可能会造成混淆。
如果您预计不会有其他任务,您可以这样做:
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
我在 windows 中编写了这段代码并且它有效但是当我将它复制到我的 raspberry pi(运行ning Jessie Debian based)时它给出了 运行time 错误
我的代码:
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
在 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
我应该如何处理 运行 两个平台上的这段代码
不能从不同线程调用 Tcl 函数。它适用于 Windows 的事实可能是因为对此条件的检查有误。
您需要做的是拥有一个与 Tk
对话的 "UI thread"。通常,此线程显式执行的所有操作是:
- 设置所有小部件和事件处理程序
- 致电
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()
如果需要,您可以从另一个线程安排函数:
import thread
def doStuff():
for i in range(1, 5):
sleep(1)
root.after(0, Task(showImage, i))
thread.start_new_thread(doStuff, ())
注意:我创建 Task
是为了轻松指定我想要 运行 showImage
和给定的 i
。通常,functools.partial
会很好,但由于 dynamic create method and decorator, got error 'functools.partial' object has no attribute '__module__'
Tkinter
一起使用
你也可以这样做:
(lambda ii: lambda: showImage(ii))(i)
但是当您稍后 return 代码时,这可能会造成混淆。
如果您预计不会有其他任务,您可以这样做:
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