2010-10-01 49 views
1

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

+0

你可能会发现这里的讨论:http://stackoverflow.com/questions/1595649/threading-in-a-pyqt-application -use-qt-threads-or-python-threads很有用,还有一些来自该问题的链接。 – jkerian 2010-10-01 19:55:26

回答

3

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

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

0

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

3

这是一个很晚的回复,但我想分享我发现的内容。这是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_())