PyQt:不能从另一个线程启动计时器

问题描述

| 我正在使用python创建Qt GUI,但出现错误:QObject :: startTimer:计时器无法从另一个线程启动。当我运行readModemSnap方法时会发生这种情况。我已经在这个问题上进行了将近一周的尝试,尝试了许多我在Web上发现的Qt线程设计方法,但是这些方法并不是很出色。
class ModemScopeWindow(QMainWindow,Ui_ModemScope):
def __init__(self,parent=None):
    super(ModemScopeWindow,self).__init__(parent)

    # Set up the user interface from Designer.
    self.setupUi(self)

    self.thread = MainThread()

    \"\"\"
    signal connections
    \"\"\"

    self.thread.newSnap.connect(self.updateScene)       
    self.thread.updateStatus.connect(self.setStatus) 


    self.thread.connectionLock.lock()
    self.thread.runLock.lock()

    self.connect(self.runButton,SIGNAL(\"clicked()\"),self.thread.runLock.unlock,Qt.QueuedConnection)

    self.connect(self.connectButton,self.thread.connectionLock.unlock,Qt.QueuedConnection)


class MainThread(QThread):

newSnap = pyqtSignal(QGraphicsScene)
updateStatus = pyqtSignal(str)
initConnect = pyqtSignal()

def __init__(self,parent = None):
    super(MainThread,self).__init__(parent)

    self.samples = []

    self.connectionLock = qmutex()
    self.runLock = qmutex()        
    self.climute = qmutex()

    self._displayCrosshairs = True
    self._displayGrid = True
    self.persistantMode = False
    self.sampleDepth = 1

    self._currentHaam = \"4\"

    color = QColor(10,255,71)
    self.plotPen = QPen(color)


    self._leftXscene = -VIEW_SIZE/2
    self._topYscene = -VIEW_SIZE/2
    self._rightXscene = VIEW_SIZE/2
    self._bottomYscene = VIEW_SIZE/2
    self._leftXworld = -10.0
    self._topYworld = 10.0
    self._rightXworld = 10.0
    self._bottomYworld = -10.0
    self._scene = QGraphicsScene(self._leftXscene,self._topYscene,VIEW_SIZE,self)

    self.start(QThread.HighestPriority)

def run(self):

    self.updateStatus.emit(\"Enter target IP address and press Connect\")

    self.connectionLock.lock()
    self.connectModem()

    while(1):
        self.runLock.lock() 
        #compile scene

        self.readModemSnap()
        self.newSnap.emit(self._scene)
        self.runLock.unlock()

def readModemSnap(self):
    self.updateStatus.emit(\"Reading Modem Snap...\")

    print len(self.samples)
    if len(self.samples) >= self.sampleDepth:# and not self.persistantMode:
        self.samples.pop(0)

    self.climute.lock()
    temp = cli.getModemSnap()
    self.climute.unlock()
    self.samples.append(temp)


    self.climute.lock()
    modType = cli.modemRead(80)
    self.climute.unlock()

    if((modType | 0x0FFFFFFF) == 0x0FFFFFFF):
        modType = \"0\";

    else:
        modType = \"%x\"%modType
        modType = str(modType)


    modType = \"0\"
    self.updateStatus.emit(\"Done\") 

    self.refresh()

    self._currentHaam = modType[0]
    if self._displayGrid:
        self.plotModulation(self._currentHaam)

    self.handleSnapshotResponse()

    self.updateStatus.emit(\"Ready to Run\")
def refresh(self):

    #delete scene
    items = self._scene.items()

    for x in items:
        self._scene.removeItem(x)

    #repaint the crosshairs
    if self._displayCrosshairs:
        self.plotLine(-VIEW_SIZE,+VIEW_SIZE,self.plotPen)
        self.plotLine(0,-VIEW_SIZE,self.plotPen)
        self.plotScaleTicks()

    #repaint grid
    if self._displayGrid:
        self.plotModulation(self._currentHaam)

    self.newSnap.emit(self._scene)

def handleSnapshotResponse(self):

    for x in range(len(self.samples)):
        for sample in self.samples[x]:
            upper = (sample >> 16) & 0xffff;
            lower = sample & 0xffff
            if (upper & 0x8000):
                upper -= 0x10000
            if (lower & 0x8000):
                lower -= 0x10000
            upper = float(upper)/128.0
            lower = float(lower)/128.0
            self.plot(upper,lower)
如您所见,我没有从另一个线程启动任何线程。我使用main来启动UI,该UI创建一个MainThread,该MainThread会在构建时自行启动。当我注释掉用于定位问题的行时,我发现在readModemSnap方法调用self.refresh()和self.handleSnapshotResponse()时发现了该问题。谁能指出我做错了什么方向?或有关QThreading的任何教程?提前致谢     

解决方法

        这是规则:除了运行Qt事件循环的主线程之外,您不能从任何线程调用任何GUI函数。当您看到有关QTimer的错误时,可能是因为GUI中的某些内容在内部使用了计时器,并且它是从另一个线程触发的。 在这种情况下,最可能的罪魁祸首是您通过工作线程在QGraphicsScene上进行操作。我会尝试重新排列,以使MainThread.reload中的代码被调用以响应newSnap信号,而不是在响应之前。