我正在开发一个使用多个线程从各种网络设备收集数据的应用程序。我正在使用PyQT在GUI上显示收集的数据。我在我的应用程序中使用常规python线程(来自线程,线程)(而不是QThread)。为了更新不同线程上的GUI,我使用了一个锁(thread.allocate_lock())。因此,每当GUI更新发生时,我都会调用lock,更新GUI。对此有何疑虑?
答案 0 :(得分:3)
我很确定在Qt中更新来自不同线程的GUI是危险的,即使你试图在自己的代码中锁定东西。首先,Qt可能正在主线程上执行自己的事件处理,并且它不会获取您的锁来保护它可能修改的对象。在Qt文档中On this page明确提到QWidget
不可重入或线程安全的事实。
我建议您将收集的数据或其处理版本发布回主线程。使用排队的信号/插槽连接,或自定义QEvent
和QApplication::postEvent
来执行此操作。在jkerian提到的上一个问题中,它表示如果你想让事件发布工作正常,你将不得不使用QThread
而不是python的线程。
答案 1 :(得分: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_())
答案 2 :(得分:-1)
我使用pyqtSignal和Python的线程。您可以创建线程,当线程完成后,它会发送信号来更新您的GUI。