2010-10-01 71 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_())