【问题标题】:PyQt5 and Wing IDE: QThread freezes applicationPyQt5 和 Wing IDE:QThread 冻结应用程序
【发布时间】:2019-04-30 18:42:57
【问题描述】:

我最近想尝试使用 Wing IDE 而不是 Eclipse+Pydev 来使用 PyQt5 编写简单的 roguelike 游戏。这个游戏使用单独的 QThread 和 QObject 来处理游戏状态而不冻结 GUI。但是,我当前的应用程序(与标准和 Eclipse 的解释器配合良好)在 Wing IDE 中冻结。在这里,我发布了代表问题的简单代码:

import sys, time
from PyQt5.QtCore import pyqtSignal, pyqtSlot, Qt, QObject, QThread
from PyQt5.QtWidgets import QApplication, QMainWindow, QPushButton, QLCDNumber, QVBoxLayout, QWidget

class Counter(QObject):
    '''
    QObject-based class which works inside separate thread and
    emits numbers from 1 to 10 to the GUI thread and then stops.
    '''

    new_value = pyqtSignal(int)
    ended = pyqtSignal()

    def __init__(self):
        QObject.__init__(self)
        self.isStopped = False

    @pyqtSlot()
    def start(self):
        self.isStopped = False
        for n in range(1, 11):
            if not self.isStopped:
                self.new_value.emit(n)
                time.sleep(0.3)
            else:
                break
        self.ended.emit()

    @pyqtSlot()
    def stop(self):
        self.isStopped = True


class SimpleWindow(QMainWindow):
    '''
    Application window with 3 buttons and 1 LCD display.
    '''

    def __init__(self):
        QMainWindow.__init__(self)

        # Adding and configuring widgets
        self.central = QWidget(self)
        self.central.resize(100, 150)
        self.resize(100, 150)
        self.layout = QVBoxLayout()
        self.central.setLayout(self.layout)
        self.start_QBtn = QPushButton()
        self.start_QBtn.setText('Start')
        self.stop_QBtn = QPushButton()
        self.stop_QBtn.setText('Stop')
        self.number_LCD = QLCDNumber()
        self.status_QBtn = QPushButton()
        self.status_QBtn.setText('Status')
        self.layout.addWidget(self.start_QBtn)
        self.layout.addWidget(self.stop_QBtn)
        self.layout.addWidget(self.status_QBtn)
        self.layout.addWidget(self.number_LCD)

        # Creating new thread and adding QObject-based object to it
        self.thread = QThread()
        self.counter = Counter()
        self.counter.moveToThread(self.thread)

        # Connecting button signals to slots
        self.start_QBtn.clicked.connect(self.thread.start)
        self.status_QBtn.clicked.connect(self.status)
        self.stop_QBtn.clicked.connect(lambda: self.counter.stop())        

        # Connecting thread signals to slots
        self.counter.new_value.connect(self.show_value)
        self.counter.ended.connect(self.thread.quit)
        self.thread.started.connect(self.counter.start)

        self.thread.start()

    @pyqtSlot(int)
    def show_value(self, number):
        '''
        Display value obtained from Counter() in the LCD widget.
        '''
        self.number_LCD.display(number)

    @pyqtSlot()
    def status(self):
        '''
        Print thread status in the console.
        '''
        print('Thread is running: ', self.thread.isRunning())


if __name__ == "__main__":
    app = QApplication(sys.argv)
    window = SimpleWindow()
    window.show()
    sys.exit(app.exec_())

应用程序启动,按预期显示从 1 到 10 的数字,然后冻结。尝试按下停止按钮时它也会冻结。有没有解决方案可以继续使用 QThread 和 Wing IDE?

我的系统是Windows 8 (x64),Python 3.7.1,Wing IDE Personal 6.1; PyQt5.11(也检查了 PyQt 5.7); Qt 5.7。

【问题讨论】:

    标签: python python-3.x pyqt qthread


    【解决方案1】:

    我可以复制它,但似乎没有正确支持 moveToThread()。这是另一个包含三个测试的测试用例,一个是 QThread 的子类,另一个是使用 moveToThread(),第三个是 QRunnable 的子类。对我来说第一个和最后一个工作以及使用 moveToThread() 的工作也不起作用:

    # From http://stackoverflow.com/questions/6783194/background-thread-with-qthread-in-pyqt
    # with minor modifications
    
    import time
    import sys
    
    from PyQt5 import QtCore
    # Hack needed to avoid _NotifyModule bug
    from PyQt5.QtCore import *
    
    # Subclassing QThread
    # http://qt-project.org/doc/latest/qthread.html
    class AThread(QtCore.QThread):
    
        def run(self):
            count = 0
            while count < 5:
                time.sleep(1)
                print("Increasing")
                count += 1
    
    # Subclassing QObject and using moveToThread
    # http://blog.qt.digia.com/blog/2007/07/05/qthreads-no-longer-abstract
    class SomeObject(QtCore.QObject):
    
        finished = QtCore.pyqtSignal()
    
        def longRunning(self):
            count = 0
            while count < 5:
                time.sleep(1)
                print("Increasing")
                count += 1
            self.finished.emit()
    
    # Using a QRunnable
    # http://qt-project.org/doc/latest/qthreadpool.html
    # Note that a QRunnable isn't a subclass of QObject and therefore does
    # not provide signals and slots.
    class Runnable(QtCore.QRunnable):
    
        def run(self):
            count = 0
            app = QtCore.QCoreApplication.instance()
            while count < 5:
                print("Increasing")
                time.sleep(1)
                count += 1
            app.quit()
    
    
    def usingQThread():
        app = QtCore.QCoreApplication([])
        thread = AThread()
        thread.finished.connect(app.exit)
        thread.start()
        sys.exit(app.exec_())
    
    def usingMoveToThread():
        app = QtCore.QCoreApplication([])
        objThread = QtCore.QThread()
        obj = SomeObject()
        obj.moveToThread(objThread)
        obj.finished.connect(objThread.quit)
        objThread.started.connect(obj.longRunning)
        objThread.finished.connect(app.exit)
        objThread.start()
        sys.exit(app.exec_())
    
    def usingQRunnable():
        app = QtCore.QCoreApplication([])
        runnable = Runnable()
        QtCore.QThreadPool.globalInstance().start(runnable)
        sys.exit(app.exec_())
    
    if __name__ == "__main__":
        usingQThread()
        #usingMoveToThread()
        #usingQRunnable()
    

    请注意,您必须取消注释要测试的那个,因为它们都调用 sys.exit 所以一次只能尝试一个。

    我会看看我们是否可以在 Wing 的未来版本中解决这个问题。感谢您发布此信息!

    【讨论】:

    • 感谢您的快速响应!第一种和最后一种方法也适用于我。
    猜你喜欢
    • 2011-08-16
    • 1970-01-01
    • 1970-01-01
    • 2019-11-04
    • 2015-05-09
    • 2013-09-26
    • 2014-09-29
    • 2016-02-10
    • 1970-01-01
    相关资源
    最近更新 更多