问题
I would like to know how to pause a QThread and then resume when I get a signal. I have read and know that I can do something like this:
def run(self):
...
self.ready=False
while not self.ready:
self.sleep(1)
...
...
@QtCore.Slot()
def set_ready(self):
self.ready = True
However, what I want to do is avoid the polling in the thread. I don't want to have to set the sleep to a short amount of time and keep checking. I want to go to sleep until I get a signal from my main thread to continue.
What I am doing in my thread is this:
(pseudo code)
with open file:
read a block of data
while data:
sendThread = send the block via UDP
read the next block of data
while not ready or sendThread.isRunning:
sleep(0.1)
In my main thread I have setup a QtNetwork.QUdpSocket
to connect readyRead to a method to handle incoming datagrams and decode them. When it gets the response that I'm waiting for it sends a signal to the set_ready
slot to tell the thread to send another datagram. I don't always know how long it will take for the other system to respond, though I will likely have some long timeout value of 30seconds or so.
Is there a way to interrupt the sleep of the thread? so I could do something like this:
sleep(30)
if not ready:
Timeout occurred stop processing
else:
Continue processing.
回答1:
You can do this pretty easily using the worker pattern of using QThreads
. There's an example in the QThread
documentation. The exact code will be a little different depending on whether you're using PyQt
or PySide
(it looks like you're using PySide
from your example).
One notable issue with PySide
compared to PyQt
is that they didn't wrap QtCore.Q_ARG, so in PyQt
, where you could normally use QMetaObject.invokeMethod
to call a slot (with arguments) on the Worker
object from the main thread, you can't do that directly in PySide
and have to create a dummy signal (ie. Main.send_signal
) to connect to the slot on the worker so you can call it from the main thread.
import time
import sys
from PySide import QtCore, QtGui
class Worker(QtCore.QObject):
send_signal = QtCore.Signal(str) # using PySide
# QtCore.pyqtSignal(str) ## using PyQt
# @QtCore.pyqtSlot(str)
@QtCore.Slot(str)
def receive_slot(self, data):
# data could be a filepath
# open file
# ... do stuff
# close file
QtCore.QThread.sleep(1) # to simulate doing stuff
self.send_signal.emit(data + ' success')
class Main(QtGui.QWidget):
send_signal = QtCore.Signal(str)
def __init__(self):
super(Main, self).__init__()
self.worker = Worker()
self.thread = QtCore.QThread(self)
self.worker.moveToThread(self.thread)
self.worker.send_signal.connect(self.receive_slot)
self.send_signal.connect(self.worker.receive_slot)
self.thread.start()
self.send_signal.emit('Start')
@QtCore.Slot(str)
def receive_slot(self, data):
print 'Main: {}'.format(data)
self.send_signal.emit('Message {}'.format(time.time()))
if __name__ == '__main__':
app = QtGui.QApplication(sys.argv)
window = Main()
window.show()
app.exec_()
来源:https://stackoverflow.com/questions/37119319/interrupting-qthread-sleep