Python3-后台线程中的键盘中断在用户将鼠标悬停在GUI窗口上之前未被主线程检测到
我已经编写了一个基于Python3Tkinter的GUI应用程序,它在后台启动一个工作线程。在工作线程完成后,它等待两秒钟(这是为了避免可能的争用情况),然后发送键盘中断,告诉主线程它可以关闭 预期行为:运行程序会启动GUI窗口,向控制台打印一些文本,然后程序自动关闭 实际行为:它不是自动关闭,而是在用户将鼠标悬停在GUI窗口区域上或按下键盘上的键后才自动关闭!除此之外,程序运行时不报告任何错误 有人知道为什么会发生这种情况,以及如何解决吗?我已经尝试将键盘中断封装到一个单独的函数中,然后通过调用调用该函数,但这会导致相同的行为 我已经能够在运行Python3.5.2的两台不同的Linux机器上重现这个问题。和3.6.6Python3-后台线程中的键盘中断在用户将鼠标悬停在GUI窗口上之前未被主线程检测到,python,python-3.x,multithreading,tkinter,Python,Python 3.x,Multithreading,Tkinter,我已经编写了一个基于Python3Tkinter的GUI应用程序,它在后台启动一个工作线程。在工作线程完成后,它等待两秒钟(这是为了避免可能的争用情况),然后发送键盘中断,告诉主线程它可以关闭 预期行为:运行程序会启动GUI窗口,向控制台打印一些文本,然后程序自动关闭 实际行为:它不是自动关闭,而是在用户将鼠标悬停在GUI窗口区域上或按下键盘上的键后才自动关闭!除此之外,程序运行时不报告任何错误 有人知道为什么会发生这种情况,以及如何解决吗?我已经尝试将键盘中断封装到一个单独的函数中,然后通过调
#/usr/bin/env蟒蛇3
导入操作系统
导入线程
导入线程作为线程
导入时间
将tkinter作为tk导入
将tkinter.scrolledtext作为scrolledtext导入
类myGUI(tk.Frame):
#此类定义图形用户界面
定义初始化(自、父、*args、**kwargs):
tk.Frame.\uuuuu init\uuuuuu(self,parent,*args,**kwargs)
self.root=parent
self.build_gui()
def构建图形用户界面(自):
#构建GUI
self.root.title('TEST')
self.root.option_add('*tearOff',FALSE')
self.grid(列=0,行=0,sticky='ew')
self.grid\u columnconfigure(0,权重=1,统一=a)
#添加文本小部件以显示日志信息
st=ScrolledText.ScrolledText(self,state='disabled')
st.configure(font='TkFixedFont')
标准网格(列=0,行=1,粘性=w',列span=4)
def worker():
“”“骨架辅助函数,在单独的线程中运行(请参见下文)”
#打印一些文本到控制台
打印(“工作!”)
#等待2秒钟以避免出现竞速情况
时间。睡眠(2)
#这会在主线程中触发键盘中断
thread.interrupt_main()
def main():
尝试:
root=tk.tk()
myGUI(根目录)
t1=线程。线程(目标=工作线程,参数=[])
t1.start()
root.mainloop()
t1.join()
除键盘中断外:
#如果子线程发出键盘中断,请关闭程序
操作系统退出(0)
main()
(Github Gist链接到上面的脚本)root.mainloop()
mainloop正在阻塞Python中的挂起(可拦截)信号,仅在执行字节码指令之间检查<代码中的code>t1.join()实际上从未执行过
由于mainloop
block等待转发的硬件中断,要解除阻止,您必须提供这些中断,例如,将鼠标悬停在您看到的窗口上。只有当解释器检测到挂起的键盘中断时
。这就是Python中信号处理的工作原理
解决一般问题可能意味着找到方法,通过外部注入解除阻塞所需的内容来解除阻塞I/O调用,或者一开始就不使用阻塞调用
对于您的具体设置,您可以使用未处理的SIGTERM终止整个过程,但当然,这样做非常非常难看,在这里也没有必要。如果您只是搜索一种超时窗口的方法,您可以使用tkinter.Tk.after
方法(显示和)超时,或者您可以摆脱mainloop
并自己运行循环()
后者可能看起来像:
def main():
root = tk.Tk()
myGUI(root)
t1 = threading.Thread(target=worker, args=[])
t1.start()
while True:
try:
root.update_idletasks()
root.update()
time.sleep(0.1)
except KeyboardInterrupt:
print('got interrupt')
break
t1.join()
谢谢,按照你的建议去掉
mainloop
,就可以了。我不知道tkinter.TK。在方法之后,我也会检查它。