[英]How to auto-close PyQt/PySide window using thread?
How can I make a PyQt5 window automatically close after 30 seconds and still keep the window respond to interaction? 如何在30秒后自动关闭PyQt5窗口,并仍然保持窗口对交互的响应?
I'm creating a thread which sleeps for 30 seconds, and then it calls the close()
function of the window. 我正在创建一个睡眠30秒的线程,然后该线程调用窗口的close()
函数。 Right now, the code hangs at self.close()
: 现在,代码挂在self.close()
:
Exception in thread Thread-1:
Traceback (most recent call last):
File "C:\Users\fredrik\.conda\envs\pysidedev_py27\lib\threading.py", line 801, in __bootstrap_inner
self.run()
File "C:\Users\fredrik\.conda\envs\pysidedev_py27\lib\threading.py", line 754, in run
self.__target(*self.__args, **self.__kwargs)
File "C:\Users\fredrik\Desktop\timer.py", line 47, in <lambda>
my_win.execute_function_threaded(func=lambda: my_win.auto_close(n=3))
File "C:\Users\fredrik\Desktop\timer.py", line 36, in auto_close
self.close() # hangs
RuntimeError: Internal C++ object (MyWindow) already deleted.
I also tried moving the threading out of the window object but then I'm still experiencing a hang on window.close()
. 我也尝试将线程移出window对象,但随后仍遇到window.close()
的挂起。
What am I doing wrong? 我究竟做错了什么?
The code must work with Python 2.7 and 3.5. 该代码必须适用于Python 2.7和3.5。
import sys
import time
from threading import Thread
try:
from PyQt5 import QtWidgets
except ImportError:
try:
from PySide2 import QtWidgets
except ImportError:
try:
from PyQt4 import QtGui as QtWidgets
except ImportError:
try:
from PySide import QtGui as QtWidgets
except ImportError:
print('giving up!')
class MyWindow(QtWidgets.QMainWindow):
"""Auto-closing window"""
def __init__(self, parent=None):
super(MyWindow, self).__init__(parent)
def closeEvent(self, event):
"""Delete object when closed"""
self.deleteLater()
def auto_close(self, n):
"""Close self in n seconds"""
print('going to sleep')
for i in range(n):
print('sleeping...')
time.sleep(1)
print('done sleeping!')
self.close() # hangs
def execute_function_threaded(self, func):
"""Run given function in thread"""
self.t = Thread(target=func)
self.t.start()
print('thread started')
app = QtWidgets.QApplication(sys.argv)
my_win = MyWindow()
my_win.show()
my_win.execute_function_threaded(func=lambda: my_win.auto_close(n=3))
sys.exit(app.exec_())
Please note that the Qt binding imports are just done like that in order to make this code run easier on your end ;) 请注意,Qt绑定的导入就是这样完成的,以使此代码在您的一端更容易运行;)
Try following code instead of my_win.execute_function_threaded
call: 尝试使用以下代码代替my_win.execute_function_threaded
调用:
class MyWindow(QtWidgets.QMainWindow):
"""Auto-closing window"""
def __init__(self, parent=None):
super(MyWindow, self).__init__(parent)
QtCore.QTimer.singleShot(30000, self.close)
The reason the original code doesn't work is because you are forbidden to call Qt GUI methods from secondary threads (Qt methods are not thread safe). 原始代码不起作用的原因是,禁止您从辅助线程调用Qt GUI方法(Qt方法不是线程安全的)。 There are several solutions to this, such as: 有几种解决方案,例如:
using a QTimer
(since QTimer
doesn't use threads, and just queues up a future event in the Qt event loop that exists in the main thread, this solution should solve the segfaults - see the answer by @ingvar ) 使用QTimer
(因为QTimer
不使用线程,而只是在主线程中存在的Qt事件循环中排队将来的事件,所以此解决方案应解决segfaults-请参阅@ingvar的答案)
using a QThread
and a custom Qt signal. 使用QThread
和自定义Qt信号。 Qt signals are thread safe, so you can connect a signal in a secondary thread to the close
slot in the primary thread. Qt信号是线程安全的,因此您可以将辅助线程中的信号连接到主线程中的close
插槽。 Then you can emit the signal from within the secondary thread after 30 seconds to trigger the close. 然后,您可以在30秒后从辅助线程内发出信号以触发关闭。
The approach you should take depends on your end goal (and how much of a 'toy' example this is), but for now I see no reason to have a secondary thread. 您应该采用的方法取决于最终目标(以及这个“玩具”示例的数量),但是到目前为止,我认为没有理由拥有辅助线程。 You should just go with @ingvar's answer :) 您应该只使用@ingvar的答案:)
PS Either way, using python threads with Qt is a bad idea. PS无论哪种方式,在Qt中使用python线程都是一个坏主意。 Stick to QThread
unless the thread is completely independent of the GUI. 除非线程完全独立于GUI,否则请坚持使用QThread
。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.