我有一种情况,我想使用单个 QThread 在不同时间运行两个(或更多)单独的方法。例如,有时我希望 QThread 运行 play(),当我完成播放时,我想断开 QThread 与此方法的连接,以便我可以将它连接到其他地方。本质上,我希望 QThread 充当任何我想与主进程并行运行的容器。
我遇到了启动 QThread 然后立即断开连接导致运行时出现奇怪行为的问题。在我发现“竞争条件”是什么意思(或者真正了解多线程)之前,我暗暗怀疑线程在断开连接之前没有完全启动。为了克服这个问题,我在 start() 和 disconnect() 调用之间添加了 5 毫秒的 sleep 时间,效果非常好。它就像一个魅力,但它不是正确的方法。
如何在不调用 sleep() 的情况下使用一个 QThread 实现此功能?
问题中的代码片段:
def play(self):
self.stateLabel.setText("Status: Playback initated ...")
self.myThread.started.connect(self.mouseRecorder.play)
self.myThread.start()
time.sleep(.005) #This is the line I'd like to eliminate
self.myThread.started.disconnect()
完整脚本:
class MouseRecord(QtCore.QObject):
finished = QtCore.pyqtSignal()
def __init__(self):
super(MouseRecord, self).__init__()
self.isRecording = False
self.cursorPath = []
@QtCore.pyqtSlot()
def record(self):
self.isRecording = True
self.cursorPath = []
while(self.isRecording):
self.cursorPath.append(win32api.GetCursorPos())
time.sleep(.02)
self.finished.emit()
def stop(self):
self.isRecording = False
@QtCore.pyqtSlot()
def play(self):
for pos in self.cursorPath:
win32api.SetCursorPos(pos)
time.sleep(.02)
print "Playback complete!"
self.finished.emit()
class CursorCapture(QtGui.QWidget):
def __init__(self):
super(CursorCapture, self).__init__()
self.mouseRecorder = MouseRecord()
self.myThread = QtCore.QThread()
self.mouseRecorder.moveToThread(self.myThread)
self.mouseRecorder.finished.connect(self.myThread.quit)
self.initUI()
def initUI(self):
self.recordBtn = QtGui.QPushButton("Record")
self.stopBtn = QtGui.QPushButton("Stop")
self.playBtn = QtGui.QPushButton("Play")
self.recordBtn.clicked.connect(self.record)
self.stopBtn.clicked.connect(self.stop)
self.playBtn.clicked.connect(self.play)
self.stateLabel = QtGui.QLabel("Status: Stopped.")
#Bunch of other GUI initialization ...
def record(self):
self.stateLabel.setText("Status: Recording ...")
self.myThread.started.connect(self.mouseRecorder.record)
self.myThread.start()
time.sleep(.005)
self.myThread.started.disconnect()
def play(self):
self.stateLabel.setText("Status: Playback initated ...")
self.myThread.started.connect(self.mouseRecorder.play)
self.myThread.start()
time.sleep(.005)
self.myThread.started.disconnect()
请您参考如下方法:
正确的方法是为每个 Action 创建新的QThread,这样就不需要 sleep 和断开连接了。现在,即使您成功消除了 sleep 调用,也可能出现以下情况:
1) 您运行play,然后断开插槽
2) 在play 完成之前运行record。在这种情况下,先前创建的线程仍在运行,并且:
If the thread is already running, this function does nothing.
(来自documentation)
但是,如果您接受这种情况并以某种方式防止同时“播放”和“录制”,那么您应该按照您自己写的那样做:“当我玩完后,我想断开连接”。所以,不仅仅是在线程启动之后,而是在它完成之后。要做到这一点试试这个:
1) 将self.mouseRecorder.finished.connect(self.myThread.quit)更改为self.mouseRecorder.finished.connect(self.threadFinished)
2) 实现:
def threadFinished(self):
self.myThread.quit()
self.myThread.started.disconnect()
