Warning: file_get_contents(/data/phpspider/zhask/data//catemap/8/python-3.x/18.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Python3-后台线程中的键盘中断在用户将鼠标悬停在GUI窗口上之前未被主线程检测到_Python_Python 3.x_Multithreading_Tkinter - Fatal编程技术网

Python3-后台线程中的键盘中断在用户将鼠标悬停在GUI窗口上之前未被主线程检测到

Python3-后台线程中的键盘中断在用户将鼠标悬停在GUI窗口上之前未被主线程检测到,python,python-3.x,multithreading,tkinter,Python,Python 3.x,Multithreading,Tkinter,我已经编写了一个基于Python3Tkinter的GUI应用程序,它在后台启动一个工作线程。在工作线程完成后,它等待两秒钟(这是为了避免可能的争用情况),然后发送键盘中断,告诉主线程它可以关闭 预期行为:运行程序会启动GUI窗口,向控制台打印一些文本,然后程序自动关闭 实际行为:它不是自动关闭,而是在用户将鼠标悬停在GUI窗口区域上或按下键盘上的键后才自动关闭!除此之外,程序运行时不报告任何错误 有人知道为什么会发生这种情况,以及如何解决吗?我已经尝试将键盘中断封装到一个单独的函数中,然后通过调

我已经编写了一个基于Python3Tkinter的GUI应用程序,它在后台启动一个工作线程。在工作线程完成后,它等待两秒钟(这是为了避免可能的争用情况),然后发送键盘中断,告诉主线程它可以关闭

预期行为:运行程序会启动GUI窗口,向控制台打印一些文本,然后程序自动关闭

实际行为:它不是自动关闭,而是在用户将鼠标悬停在GUI窗口区域上或按下键盘上的键后才自动关闭!除此之外,程序运行时不报告任何错误

有人知道为什么会发生这种情况,以及如何解决吗?我已经尝试将键盘中断封装到一个单独的函数中,然后通过调用调用该函数,但这会导致相同的行为

我已经能够在运行Python3.5.2的两台不同的Linux机器上重现这个问题。和3.6.6

#/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。在
方法之后,我也会检查它。