PyQt:不能从另一个线程启动计时器 [英] PyQt: timers cannot be started from another thread

查看:93
本文介绍了PyQt:不能从另一个线程启动计时器的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在使用python创建Qt GUI,但出现错误:QObject :: startTimer:无法从另一个线程启动计时器.当我运行readModemSnap方法时会发生这种情况.我已经进行了将近一个星期的尝试,尝试了许多我在Web上发现的Qt线程设计方法,但这些设计都不是什么.

I am making a Qt GUI with python and i am getting the error: QObject::startTimer: timers cannot be started from another thread. It occurs when I run the readModemSnap method. I've been working on this for almost a week trying many different design patterns for threading in Qt that i've found on the web but nothign works.

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, SIGNAL("clicked()"), 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, 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,0,+VIEW_SIZE,0, self.plotPen)
        self.plotLine(0, -VIEW_SIZE,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的任何教程?预先感谢

as you can see Im not starting any thread from another thread. i use the main to start the UI which creates a MainThread that starts itself upon construction. When i commented lines out to localize the problem I found that its when i call self.refresh() and self.handleSnapshotResponse() in the readModemSnap method. Can anyone point me in the direction of what im doing wrong? or any tutorials on QThreading? thanks in advance

推荐答案

这是规则:除运行Qt事件循环的主线程以外,您不能从任何线程调用任何GUI函数.当您看到有关QTimer的错误时,可能是因为GUI中的某个内部使用了计时器,并且该计时器是从另一个线程触发的.

This is the rule: you cannot call any GUI functions from any thread other than the main thread running the Qt event loop. When you see errors about QTimer, it's probably because something in the GUI uses a timer internally and it is being triggered from another thread.

您遇到的最可能的罪魁祸首是您是通过工作线程在QGraphicsScene上进行操作的.我会尝试重新排列,以使MainThread.reload中的代码被调用以响应newSnap信号,而不是在响应之前.

The most likely culprit in your case is that you are operating on a QGraphicsScene from the worker thread. I would try rearranging such that the code in MainThread.reload is called in response to the newSnap signal, rather than before it.

这篇关于PyQt:不能从另一个线程启动计时器的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆