开发者

PyQT and threads

I am developing an application that uses multiple threads to gather da开发者_如何学运维ta from a variety of network devices. I'm using PyQT to display the collected data on a GUI. I am using regular python threads (from thread, threading) in my app (instead of QThread). In order to update the GUI on the different threads, I use a lock (thread.allocate_lock()). So, anytime a GUI update will happen, I call with lock, update GUI. Any concerns about this?


I'm pretty sure that updating the GUI from different threads is dangerous in Qt, even if you try to lock things in your own code. For one thing, Qt might be doing its own event processing on the main thread, and it will not acquire your lock to protect objects that it might modify. On this page in the Qt docs, the fact that QWidget is not reentrant or thread-safe is explicitly mentioned.

I recommend that you post the collected data, or a processed version of it, back to the main thread. Use a queued signal/slot connection, or a custom QEvent and QApplication::postEvent to do this. In the previous question that jkerian mentions, it says that you'll have to use QThread instead of python's threads if you want event posting to work correctly.


This is a late reply but I wanted to share what I found. This is code from WickedDevice Blog that I found useful to understand threads and 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_())


I use pyqtSignal and Python's threading. You can create threads and when the thread is completed have it send a signal to update your GUI.

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜