如何使用线程自动粘液pyqt/pyside窗口



如何在30秒后自动关闭pyqt5窗口,并且仍然保持窗口对交互作用?

我正在创建一个线程,该线程可睡30秒,然后调用窗口的close()功能。现在,代码悬挂在self.close()

Exception in thread Thread-1:
Traceback (most recent call last):
  File "C:Usersfredrik.condaenvspysidedev_py27libthreading.py", line 801, in __bootstrap_inner
    self.run()
  File "C:Usersfredrik.condaenvspysidedev_py27libthreading.py", line 754, in run
    self.__target(*self.__args, **self.__kwargs)
  File "C:UsersfredrikDesktoptimer.py", line 47, in <lambda>
    my_win.execute_function_threaded(func=lambda: my_win.auto_close(n=3))
  File "C:UsersfredrikDesktoptimer.py", line 36, in auto_close
    self.close()  # hangs
RuntimeError: Internal C++ object (MyWindow) already deleted.

我还尝试将螺纹从窗口对象移出,但后来我仍然挂在window.close()上。

我在做什么错?

代码必须与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_())

请注意,QT绑定导入只是这样完成的,以使该代码在您的末端更容易运行;(

尝试以下代码而不是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)

原始代码不起作用的原因是因为您被禁止从辅助线程调用QT GUI方法(QT方法不是线程安全的(。有几种解决方案,例如:

  • 使用QTimer(因为QTimer不使用线程,并且仅在主线程中存在的QT事件循环中排队将来的事件,因此该解决方案应求解segfaults-请参阅@ingvar的答案(

  • 使用QThread和自定义QT信号。QT信号是安全的,因此您可以将辅助线程中的信号连接到主线程中的close插槽。然后,您可以在30秒后从辅助螺纹内部发射信号以触发关闭。

您应该采用的方法取决于您的最终目标(以及"玩具"的示例是多少(,但是现在我认为没有理由拥有辅助线程。您应该随 @Ingvar的答案:(

P.S。无论哪种方式,使用QT使用Python线程都是一个坏主意。坚持使用QThread,除非线程完全独立于GUI。