【问题标题】:PyQT and threadsPyQT 和线程
【发布时间】:2011-04-20 01:04:14
【问题描述】:

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

【问题讨论】:

标签: python multithreading pyqt


【解决方案1】:

我很确定在 Qt 中从不同的线程更新 GUI 是危险的,即使您尝试在自己的代码中锁定内容。一方面,Qt 可能在主线程上进行自己的事件处理,它不会获取你的锁来保护它可能修改的对象。 On this page 在 Qt 文档中,明确提到了 QWidget 不是可重入或线程安全的事实。

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

【讨论】:

    【解决方案2】:

    这是一个迟到的回复,但我想分享我的发现。这是来自 WickedDevice 博客的代码,我发现它有助于理解线程和 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_())
    

    【讨论】:

      【解决方案3】:

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

      【讨论】:

        猜你喜欢
        • 2017-05-15
        • 1970-01-01
        • 2016-07-01
        • 1970-01-01
        • 1970-01-01
        • 2016-11-17
        • 2018-01-15
        • 2012-08-10
        • 2014-06-16
        相关资源
        最近更新 更多