Ubuntu下含QOpenGLWidget的PyQt应用Ctrl-C终止失效的解决方法
问题:PyQt应用包含QOpenGLWidget时,无法通过终端Ctrl-C终止
我的PyQt应用主文件代码如下:
#!/usr/bin/env python3 from PyQt5.QtWidgets import QApplication import signal import sys from main_window import MainWindow if __name__ == "__main__": signal.signal(signal.SIGINT, signal.SIG_DFL) app = QApplication([]) window = MainWindow() window.show() app.exec()
在Ubuntu终端中按下Ctrl-C可正常终止该应用,但当应用创建QOpenGLWidget后,Ctrl-C操作完全无效。
我尝试了自定义信号处理函数,但函数从未被调用:
def signal_handler(signum, frame): """Handle SIGINT signal""" print("\nReceived SIGINT, closing application...") QApplication.instance().quit() if __name__ == "__main__": signal.signal(signal.SIGINT, signal_handler) ...
请问如何通过终端Ctrl-C终止含QOpenGLWidget的PyQt应用?
解决方案
原因
QOpenGLWidget会启动OpenGL渲染线程,导致Qt的事件循环长时间被OpenGL的渲染操作占用。而Python的信号处理机制仅在Python解释器的字节码执行间隙处理信号,当Qt事件循环一直处理OpenGL相关事件时,没有机会回到Python解释器的循环,因此注册的信号处理函数无法被触发。
解决方法:用QTimer定期唤醒Python解释器
通过添加一个定时触发的QTimer,让Qt事件循环每隔一段时间执行一个空的Python函数,给Python解释器留出处理信号的时间。修改后的代码如下:
#!/usr/bin/env python3 from PyQt5.QtWidgets import QApplication from PyQt5.QtCore import QTimer import signal import sys from main_window import MainWindow def signal_handler(signum, frame): """Handle SIGINT signal""" print("\nReceived SIGINT, closing application...") QApplication.instance().quit() if __name__ == "__main__": # 注册SIGINT信号处理函数 signal.signal(signal.SIGINT, signal_handler) app = QApplication([]) # 创建定时器,每隔100ms触发一次空函数,唤醒Python解释器处理信号 signal_timer = QTimer() signal_timer.start(100) signal_timer.timeout.connect(lambda: None) window = MainWindow() window.show() app.exec()
原理
QTimer的timeout事件会让Qt事件循环调用Python的lambda函数,此时Python解释器会有机会检查并处理待处理的信号(比如SIGINT),从而触发我们注册的signal_handler函数,最终调用QApplication.quit()终止应用。
内容的提问来源于stack exchange,提问作者spraff
相关产品推荐
相关产品推荐

