PyQT和线程

问题描述 投票:1回答:3

我正在开发一个使用多个线程从各种网络设备收集数据的应用程序。我正在使用PyQT在GUI上显示收集的数据。我在我的应用程序中使用常规python线程(来自线程,线程)(而不是QThread)。为了更新不同线程上的GUI,我使用了一个锁(thread.allocate_lock())。因此,每当GUI更新发生时,我都会调用lock,更新GUI。对此有何担忧?

python multithreading pyqt
3个回答
3
投票

我很确定在Qt​​中更新来自不同线程的GUI是危险的,即使你试图在你自己的代码中锁定东西。首先,Qt可能正在主线程上执行自己的事件处理,并且它不会获取您的锁来保护它可能修改的对象。 Qt文档中的On this page,明确提到QWidget不可重入或线程安全的事实。

我建议您将收集的数据或其处理版本发布回主线程。使用排队的信号/插槽连接,或自定义QEventQApplication::postEvent来执行此操作。在jkerian提到的上一个问题中,它说如果你想让事件发布正常工作,你将不得不使用QThread而不是python的线程。


2
投票

这是一个迟到的回复,但我想分享我发现的。这是来自WickedDevice Blog的代码,我发现它对理解线程和PyQt很有用:

#authors: Dirk Swart, Doudewijn Rempt, Jacob Hallen

import sys, time, threading, random, Queue
from PyQt4 import QtGui, QtCore as qt
import serial

SERIALPORT = 'COM6'

class GuiPart(QtGui.QMainWindow):

    def __init__(self, queue, endcommand, *args):
        QtGui.QMainWindow.__init__(self, *args)
        self.setWindowTitle('Arduino Serial Demo')
        self.queue = queue
        # We show the result of the thread in the gui, instead of the console
        self.editor = QtGui.QTextEdit(self)
        self.setCentralWidget(self.editor)
        self.endcommand = endcommand    

    def closeEvent(self, ev):
        self.endcommand()

    def processIncoming(self):
        """
        Handle all the messages currently in the queue (if any).
        """
        while self.queue.qsize():
            try:
                msg = self.queue.get(0)
                # Check contents of message and do what it says
                # As a test, we simply print it
                self.editor.insertPlainText(str(msg))
            except Queue.Empty:
                pass

class ThreadedClient:
    """
    Launch the main part of the GUI and the worker thread. periodicCall and
    endApplication could reside in the GUI part, but putting them here
    means that you have all the thread controls in a single place.
    """
    def __init__(self):
        # Create the queue
        self.queue = Queue.Queue()

        # Set up the GUI part
        self.gui=GuiPart(self.queue, self.endApplication)
        self.gui.show()

        # A timer to periodically call periodicCall :-)
        self.timer = qt.QTimer()
        qt.QObject.connect(self.timer,
                           qt.SIGNAL("timeout()"),
                           self.periodicCall)
        # Start the timer -- this replaces the initial call to periodicCall
        self.timer.start(100)

        # Set up the thread to do asynchronous I/O
        # More can be made if necessary
        self.running = 1
        self.thread1 = threading.Thread(target=self.workerThread1)
        self.thread1.start()

    def periodicCall(self):
        """
        Check every 100 ms if there is something new in the queue.
        """
        self.gui.processIncoming()
        if not self.running:
            root.quit()

    def endApplication(self):
        self.running = 0

    def workerThread1(self):
        """
        This is where we handle the asynchronous I/O. 
        Put your stuff here.
        """
        while self.running:
            #This is where we poll the Serial port. 
            #time.sleep(rand.random() * 0.3)
            #msg = rand.random()
            #self.queue.put(msg)
            ser = serial.Serial(SERIALPORT, 115200)
            msg = ser.readline();
            if (msg):
                self.queue.put(msg)
            else: pass  
            ser.close()



if __name__ == "__main__":
    #rand = random.Random()
    root = QtGui.QApplication(sys.argv)
    client = ThreadedClient()
    sys.exit(app.exec_())

-1
投票

我使用pyqtSignal和Python的线程。您可以创建线程,当线程完成后,它会发送信号来更新您的GUI。

© www.soinside.com 2019 - 2024. All rights reserved.