PyQt:如何处理QThread?
PyQt: How to deal with QThread?
在下面的代码中我尝试处理QThread
。在此可执行示例中,有三个按钮:第一个用于启动,第二个用于停止,第三个用于关闭。好吧,当我开始任务时,它运行起来就像一个魅力。 BUT 当我希望 while 循环停止时,我单击停止按钮。现在,有一个问题:while 循环不会停止。
你看,停止按钮发出一个信号来调用 TestTask()
上的 stop()
方法。
怎么了?
from sys import argv
from PyQt4.QtCore import QObject, pyqtSignal, QThread, Qt, QMutex
from PyQt4.QtGui import QDialog, QApplication, QPushButton, \
QLineEdit, QFormLayout, QTextEdit
class TestTask(QObject):
def __init__(self, parent=None):
QObject.__init__(self, parent)
self._mutex = QMutex()
self._end_loop = True
def init_object(self):
while self._end_loop:
print "Sratus", self._end_loop
def stop(self):
self._mutex.lock()
self._end_loop = False
self._mutex.unlock()
class Form(QDialog):
stop_loop = pyqtSignal()
def __init__(self, parent=None):
QDialog.__init__(self, parent)
self.init_ui()
def init_ui(self):
self.pushButton_start_loop = QPushButton()
self.pushButton_start_loop.setText("Start Loop")
self.pushButton_stop_loop = QPushButton()
self.pushButton_stop_loop.setText("Stop Loop")
self.pushButton_close = QPushButton()
self.pushButton_close.setText("Close")
layout = QFormLayout()
layout.addWidget(self.pushButton_start_loop)
layout.addWidget(self.pushButton_stop_loop)
layout.addWidget(self.pushButton_close)
self.setLayout(layout)
self.setWindowTitle("Tes Window")
self.init_signal_slot_pushButton()
def start_task(self):
self.task_thread = QThread(self)
self.task_thread.work = TestTask()
self.task_thread.work.moveToThread(self.task_thread)
self.task_thread.started.connect(self.task_thread.work.init_object)
self.stop_loop.connect(self.task_thread.work.stop)
self.task_thread.start()
def stop_looping(self):
self.stop_loop.emit()
def init_signal_slot_pushButton(self):
self.pushButton_start_loop.clicked.connect(self.start_task)
self.pushButton_stop_loop.clicked.connect(self.stop_looping)
self.pushButton_close.clicked.connect(self.close)
app = QApplication(argv)
form = Form()
form.show()
app.exec_()
将stop_loop
信号转换为事件发送给信号接收者的线程。但是您的工作对象是 运行 阻塞 while-loop,这会阻止线程处理其 event-queue 中的任何未决事件。所以连接到 stop_loop
信号的插槽将永远不会被调用。
要解决此问题,您可以在 while-loop 中调用 processEvents
以允许线程处理其未决事件:
def init_object(self):
while self._end_loop:
QThread.sleep(1)
QApplication.processEvents()
print "Status", self._end_loop
或者,您可以直接调用 worker 的 stop()
方法而不是发出信号。严格来说,这不是thread-safe,但只有当多个线程可以同时调用stop()
时才会出现问题。因此,更正确的做法是使用互斥锁来保护被更改的值:
class TestTask(QObject):
def __init__(self, parent=None):
QObject.__init__(self, parent)
self._mutex = QtCore.QMutex()
self._end_loop = True
def stop(self):
self._mutex.lock()
self._end_loop = False
self._mutex.unlock()
现在直接从主线程调用stop()
是thread-safe。
在下面的代码中我尝试处理QThread
。在此可执行示例中,有三个按钮:第一个用于启动,第二个用于停止,第三个用于关闭。好吧,当我开始任务时,它运行起来就像一个魅力。 BUT 当我希望 while 循环停止时,我单击停止按钮。现在,有一个问题:while 循环不会停止。
你看,停止按钮发出一个信号来调用 TestTask()
上的 stop()
方法。
怎么了?
from sys import argv
from PyQt4.QtCore import QObject, pyqtSignal, QThread, Qt, QMutex
from PyQt4.QtGui import QDialog, QApplication, QPushButton, \
QLineEdit, QFormLayout, QTextEdit
class TestTask(QObject):
def __init__(self, parent=None):
QObject.__init__(self, parent)
self._mutex = QMutex()
self._end_loop = True
def init_object(self):
while self._end_loop:
print "Sratus", self._end_loop
def stop(self):
self._mutex.lock()
self._end_loop = False
self._mutex.unlock()
class Form(QDialog):
stop_loop = pyqtSignal()
def __init__(self, parent=None):
QDialog.__init__(self, parent)
self.init_ui()
def init_ui(self):
self.pushButton_start_loop = QPushButton()
self.pushButton_start_loop.setText("Start Loop")
self.pushButton_stop_loop = QPushButton()
self.pushButton_stop_loop.setText("Stop Loop")
self.pushButton_close = QPushButton()
self.pushButton_close.setText("Close")
layout = QFormLayout()
layout.addWidget(self.pushButton_start_loop)
layout.addWidget(self.pushButton_stop_loop)
layout.addWidget(self.pushButton_close)
self.setLayout(layout)
self.setWindowTitle("Tes Window")
self.init_signal_slot_pushButton()
def start_task(self):
self.task_thread = QThread(self)
self.task_thread.work = TestTask()
self.task_thread.work.moveToThread(self.task_thread)
self.task_thread.started.connect(self.task_thread.work.init_object)
self.stop_loop.connect(self.task_thread.work.stop)
self.task_thread.start()
def stop_looping(self):
self.stop_loop.emit()
def init_signal_slot_pushButton(self):
self.pushButton_start_loop.clicked.connect(self.start_task)
self.pushButton_stop_loop.clicked.connect(self.stop_looping)
self.pushButton_close.clicked.connect(self.close)
app = QApplication(argv)
form = Form()
form.show()
app.exec_()
将stop_loop
信号转换为事件发送给信号接收者的线程。但是您的工作对象是 运行 阻塞 while-loop,这会阻止线程处理其 event-queue 中的任何未决事件。所以连接到 stop_loop
信号的插槽将永远不会被调用。
要解决此问题,您可以在 while-loop 中调用 processEvents
以允许线程处理其未决事件:
def init_object(self):
while self._end_loop:
QThread.sleep(1)
QApplication.processEvents()
print "Status", self._end_loop
或者,您可以直接调用 worker 的 stop()
方法而不是发出信号。严格来说,这不是thread-safe,但只有当多个线程可以同时调用stop()
时才会出现问题。因此,更正确的做法是使用互斥锁来保护被更改的值:
class TestTask(QObject):
def __init__(self, parent=None):
QObject.__init__(self, parent)
self._mutex = QtCore.QMutex()
self._end_loop = True
def stop(self):
self._mutex.lock()
self._end_loop = False
self._mutex.unlock()
现在直接从主线程调用stop()
是thread-safe。