PyQt5 和 Wing IDE:QThread 冻结应用程序
PyQt5 and Wing IDE: QThread freezes application
我最近想尝试使用 Wing IDE 而不是 Eclipse+Pydev 来使用 PyQt5 编写简单的 roguelike 游戏。该游戏使用单独的 QThread 和其中的 QObject 来处理游戏状态而不冻结 GUI。但是,我当前的应用程序在标准和 Eclipse 的解释器上运行良好,但在 Wing IDE 中冻结。这里我post代表问题的简单代码:
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 with Wing IDE?
我的系统是Windows 8 (x64), Python 3.7.1, Wing IDE Personal 6.1; PyQt5.11(也用 PyQt 5.7 检查过); Qt 5.7.
我可以复制这个,看起来 moveToThread() 没有得到正确支持。这是另一个包含三个测试的测试用例,一个是 QThread 的子类,另一个是使用 moveToThread() 的子类,第三个是 QRunnable 的子类。第一个也是最后一个对我有用,而使用 moveToThread() 的那个也不起作用:
# From
# 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 的未来版本中解决这个问题。感谢您发帖!
我最近想尝试使用 Wing IDE 而不是 Eclipse+Pydev 来使用 PyQt5 编写简单的 roguelike 游戏。该游戏使用单独的 QThread 和其中的 QObject 来处理游戏状态而不冻结 GUI。但是,我当前的应用程序在标准和 Eclipse 的解释器上运行良好,但在 Wing IDE 中冻结。这里我post代表问题的简单代码:
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 with Wing IDE?
我的系统是Windows 8 (x64), Python 3.7.1, Wing IDE Personal 6.1; PyQt5.11(也用 PyQt 5.7 检查过); Qt 5.7.
我可以复制这个,看起来 moveToThread() 没有得到正确支持。这是另一个包含三个测试的测试用例,一个是 QThread 的子类,另一个是使用 moveToThread() 的子类,第三个是 QRunnable 的子类。第一个也是最后一个对我有用,而使用 moveToThread() 的那个也不起作用:
# From
# 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 的未来版本中解决这个问题。感谢您发帖!