问题描述
这是测试用例...
将 Tkinter 导入为 tk导入线程从时间导入睡眠如果 __name__ == '__main__':t = tk.Tk()thread.start_new_thread(t.mainloop, ())# t.iconbitmap('icon.ico')b = tk.Button(text='test', command=exit)b.grid(row=0)而 1:睡觉(1)
此代码有效.取消注释 t.iconbitmap 行并锁定.以您喜欢的任何方式重新安排;它会锁定.
当存在图标时,如何防止 tk.mainloop 锁定 GIL?
目标是 win32 和 Python 2.6.2.
我相信你不应该在不同的线程上执行主循环.AFAIK,主循环应该在创建小部件的同一线程上执行.
我熟悉的 GUI 工具包(Tkinter、.NET Windows 窗体)是这样的:您只能从一个线程操作 GUI.
在 Linux 上,您的代码引发异常:
self.tk.mainloop(n)运行时错误:从不同的公寓调用 Tcl以下之一将起作用(没有额外的线程):
如果 __name__ == '__main__':t = tk.Tk()t.iconbitmap('icon.ico')b = tk.Button(text='test', command=exit)b.grid(row=0)t.mainloop()
额外的线程:
def threadmain():t = tk.Tk()t.iconbitmap('icon.ico')b = tk.Button(text='test', command=exit)b.grid(row=0)t.mainloop()如果 __name__ == '__main__':thread.start_new_thread(threadmain, ())而 1:睡觉(1)
如果您需要从 tkinter 线程外部与 tkinter 进行通信,我建议您设置一个计时器来检查工作队列.
这是一个例子:
将 Tkinter 导入为 tk导入线程从时间导入睡眠导入队列request_queue = Queue.Queue()result_queue = Queue.Queue()def submit_to_tkinter(callable, *args, **kwargs):request_queue.put((callable, args, kwargs))返回 result_queue.get()t = 无定义线程主():全局 t定义计时器():尝试:callable, args, kwargs = request_queue.get_nowait()除了 Queue.Empty:经过别的:打印队列中的东西"retval = callable(*args, **kwargs)result_queue.put(retval)t.after(500, timertick)t = tk.Tk()t.configure(宽=640,高=480)b = tk.Button(text='test', name='button', command=exit)b.place(x=0, y=0)计时器()t.mainloop()定义 foo():t.title("你好世界")定义栏(button_text):t.children["button"].configure(text=button_text)def get_button_text():返回 t.children["button"]["text"]如果 __name__ == '__main__':thread.start_new_thread(threadmain, ())触发器 = 0而 1:触发 += 1如果触发器 == 3:submit_to_tkinter(foo)如果触发器 == 5:submit_to_tkinter(酒吧,改变")如果触发器 == 7:打印 submit_to_tkinter(get_button_text)睡觉(1)
Here's the test case...
import Tkinter as tk
import thread
from time import sleep
if __name__ == '__main__':
t = tk.Tk()
thread.start_new_thread(t.mainloop, ())
# t.iconbitmap('icon.ico')
b = tk.Button(text='test', command=exit)
b.grid(row=0)
while 1:
sleep(1)
This code works. Uncomment the t.iconbitmap line and it locks. Re-arrange it any way you like; it will lock.
How do I prevent tk.mainloop locking the GIL when there is an icon present?
The target is win32 and Python 2.6.2.
I believe you should not execute the main loop on a different thread. AFAIK, the main loop should be executed on the same thread that created the widget.
The GUI toolkits that I am familiar with (Tkinter, .NET Windows Forms) are that way: You can manipulate the GUI from one thread only.
On Linux, your code raises an exception:
self.tk.mainloop(n) RuntimeError: Calling Tcl from different appartment
One of the following will work (no extra threads):
if __name__ == '__main__':
t = tk.Tk()
t.iconbitmap('icon.ico')
b = tk.Button(text='test', command=exit)
b.grid(row=0)
t.mainloop()
With extra thread:
def threadmain():
t = tk.Tk()
t.iconbitmap('icon.ico')
b = tk.Button(text='test', command=exit)
b.grid(row=0)
t.mainloop()
if __name__ == '__main__':
thread.start_new_thread(threadmain, ())
while 1:
sleep(1)
If you need to do communicate with tkinter from outside the tkinter thread, I suggest you set up a timer that checks a queue for work.
Here is an example:
import Tkinter as tk
import thread
from time import sleep
import Queue
request_queue = Queue.Queue()
result_queue = Queue.Queue()
def submit_to_tkinter(callable, *args, **kwargs):
request_queue.put((callable, args, kwargs))
return result_queue.get()
t = None
def threadmain():
global t
def timertick():
try:
callable, args, kwargs = request_queue.get_nowait()
except Queue.Empty:
pass
else:
print "something in queue"
retval = callable(*args, **kwargs)
result_queue.put(retval)
t.after(500, timertick)
t = tk.Tk()
t.configure(width=640, height=480)
b = tk.Button(text='test', name='button', command=exit)
b.place(x=0, y=0)
timertick()
t.mainloop()
def foo():
t.title("Hello world")
def bar(button_text):
t.children["button"].configure(text=button_text)
def get_button_text():
return t.children["button"]["text"]
if __name__ == '__main__':
thread.start_new_thread(threadmain, ())
trigger = 0
while 1:
trigger += 1
if trigger == 3:
submit_to_tkinter(foo)
if trigger == 5:
submit_to_tkinter(bar, "changed")
if trigger == 7:
print submit_to_tkinter(get_button_text)
sleep(1)
这篇关于当图标被加载并且 tk.mainloop 在线程中时,Tkinter 锁定 Python的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!