Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/python/290.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Python PyQt5“;计时器不能从另一个线程启动;更改QLabel的大小时出错_Python_Multithreading_Timer_Pyqt_Pyqt5 - Fatal编程技术网

Python PyQt5“;计时器不能从另一个线程启动;更改QLabel的大小时出错

Python PyQt5“;计时器不能从另一个线程启动;更改QLabel的大小时出错,python,multithreading,timer,pyqt,pyqt5,Python,Multithreading,Timer,Pyqt,Pyqt5,Python 3.5中的PyQt5有一个奇怪的问题。 我有两个类,FrontEnd(QWidget)和TimerThread(Thread)。我在FrontEnd的init函数中定义了许多QLabel,所有这些都可以正常工作 所示为前端的相关少数功能: def update_ui(self): ret, frame = self.cam_capture.read() if self.results_pending: if not path.isfile('out

Python 3.5中的PyQt5有一个奇怪的问题。 我有两个类,
FrontEnd(QWidget)
TimerThread(Thread)
。我在
FrontEnd
的init函数中定义了许多
QLabel
,所有这些都可以正常工作

所示为
前端的相关少数功能:

def update_ui(self):
    ret, frame = self.cam_capture.read()

    if self.results_pending:
        if not path.isfile('output.jpg'):
            self.results_pending = False
            with open('.out') as content_file:
                content = content_file.readlines()[2:-2]
            system('rm .out')
            self.handle_image_classification(content)

    if self.take_picture:
        cv2.imwrite('output.jpg', frame)
        self.user_prompt.setText('Please wait...')
        system('./classifyimage.py --mean mean.binaryproto --nogpu --labels labels.txt model.caffemodel deploy.prototxt output.jpg > .out && rm output.jpg')
        self.take_picture = False
        self.results_pending = True

    image = QImage(frame, frame.shape[1], frame.shape[0], QImage.Format_RGB888).rgbSwapped()
    pix = QPixmap.fromImage(image)
    self.video_frame.setPixmap(pix)

def update_bar_graph(self, data):
    palette = QPalette()
    palette.setColor(QPalette.Background, Qt.white)
    for i in range(0, 8):
        self.bar_graph_labels[i].setText(str(data[i]) + "%")
        height = int(data[i] * 5)
        self.bar_graph[i].setFixedSize(self.bar_width, height)
        self.bar_graph[i].move(1280 + (i * (self.bar_width + self.bar_spacing)), 640 - height)

def handle_image_classification(self, raw_output):
    data = [None] * 8
    for i in range(0, len(raw_output)):
        raw_output[i] = raw_output[i].strip()
        data[int(raw_output[i][-2]) - 1] = float(raw_output[i][:-10])
    self.update_bar_graph(data)
而整个时间阅读课:

class TimerThread(Thread):
    front_end = None

    def __init__(self, event):
        Thread.__init__(self)
        self.stopped = event

    def run(self):
        while not self.stopped.wait(0.02):    
            FrontEnd.update_ui(self.front_end)
(时间读取的
前端
元素在
前端
的初始设置)

问题出在
update\u bar\u graph
功能中。当
setFixedSize
调用被注释掉时,程序运行正常,尽管没有在我的应用程序中正确显示条形图的条形图(即
QLabels
)。
move
功能似乎运行正常。但是,
setFixedSize
调用会导致以下错误:

QObject::startTimer: Timers cannot be started from another thread
QObject::startTimer: Timers cannot be started from another thread
QObject::killTimer: Timers cannot be stopped from another thread
QObject::startTimer: Timers cannot be started from another thread
我完全不知道为什么会发生这种情况,也不知道为什么性质相似的
move
函数可以正常工作。任何帮助都将不胜感激。 (如果我应该使用不同种类的计时器类或不同方法在PyQt中绘制大矩形,我愿意接受任何此类建议)

编辑:

这是一些奇怪的东西。第二天我运行了两次,代码没有任何更改。(我想…)有一次条形图没有显示,但没有抛出错误。另一次我得到这个:

7fdfaf931000-7fdfaf932000 r--p 0007a000 08:07 655633                     /usr/lib/x86_64-linux-gnu/libQt5DBus.so.5.5.1
7fdfaf932000-7fdfaf933000 rw-p 0007b000 08:07 655633                     /usr/lib/x86_64-linux-gnu/libQt5DBus.so.5.5.1
7fdfaf933000-7fdfaf934000 rw-p 00000000 00:00 0 
7fdfaf934000-7fdfaf971000 r-xp 00000000 08:07 667112                     /usr/lib/x86_64-linux-gnu/libxkbcommon.so.0.0.0
7fdfaf971000-7fdfafb70000 ---p 0003d000 08:07 667112                     /usr/lib/x86_64-linux-gnu/libxkbcommon.so.0.0.0
7fdfafb70000-7fdfafb72000 r--p 0003c000 08:07 667112                     /usr/lib/x86_64-linux-gnu/libxkbcommon.so.0.0.0
7fdfafb72000-7fdfafb73000 rw-p 0003e000 08:07 667112                     /usr/lib/x86_64-linux-gnu/libxkbcommon.so.0.0.0
7fdfafb73000-7fdfafb7a000 r-xp 00000000 08:07 667110                     /usr/lib/x86_64-linux-gnu/libxkbcommon-x11.so.0.0.0
7fdfafb7a000-7fdfafd79000 ---p 00007000 08:07 667110                     /usr/lib/x86_64-linux-gnu/libxkbcommon-x11.so.0.0.0
我想我可能在PyQt5中发现了一个bug。

正如@your代码所提到的,它不是线程安全的。这很可能是错误行为的来源,在进一步调试(相关)之前一定要修复

它是线程不安全的原因是因为您直接从辅助线程与GUI对象交互。相反,您应该将一个信号从线程发送到主线程中的一个插槽,在那里您可以安全地更新GUI。但是,这要求您使用
QThread
,根据推荐使用该线程

这需要进行以下更改:

class TimerThread(QThread):
    update = pyqtSignal()

    def __init__(self, event):
        QThread.__init__(self)
        self.stopped = event

    def run(self):
        while not self.stopped.wait(0.02):    
            self.update.emit()

class FrontEnd(QWidget):
    def __init__(self):
        super().__init__()

        ... # code as in your original

        stop_flag = Event()    
        self.timer_thread = TimerThread(stop_flag)
        self.timer_thread.update.connect(self.update_ui)
        self.timer_thread.start()
我还修改了您的代码,以便它在
FrontEnd
对象中存储对
TimerThread
的引用,从而使线程不会被垃圾收集


我还要补充一点,这是一种每0.02秒触发一次更新的过于复杂的方式。您可以使用
QTimer
来调用
update\u ui
方法并完全丢弃线程,但我采用的方法是,您可能希望稍后对线程执行更复杂的操作,因此已经演示了如何安全地执行此操作

顺便说一句,一个友好的建议是,如果你打算在Windows上运行PyQt程序,请尽可能远离
QThread
s。它会导致随机崩溃,让你发疯。你不应该调用更新QObject的方法。您应该创建一个信号,将其连接到一个插槽,然后您可以安全地从另一个线程发出该信号,更新将在对象所在的事件循环中处理。@TheQuantumPhysicator-不,如果发生这种情况,则可能是您没有真正理解如何在Qt中使用线程,并且您正在做一些错误的事情。将编程错误归咎于Qt对任何人都没有帮助。@mata我已经使用Qt 6年了。我不是新手。C++上的QThread很好。但是Python上的QThread充满了bug。欢迎你自己尝试,并承担后果。我不仅遭受了这种痛苦,而且我还询问了许多随机崩溃的人,他们的背后总是有一个QThread。我甚至对它进行了WinGDB调试,并表明QThread是邪恶的根源。你可以试着对我抱着理想主义的态度,声称我错了的可能性更大,但你只有像我一样在这件事上浪费一些时间,你才会知道真相。多处理万岁@量子物理学家你有什么具体的例子/证据支持你的说法吗?我非常有兴趣看到崩溃的最小工作示例。我见过Pyside做坏事,但如果代码实际上是线程安全的,PyQt从来没有给我带来麻烦。如果你没有证据表明你可以提出与所发布的特定问题相关的问题,那么我真的不认为随机问题的评论是进行此类指控的地方。回答得很好!