PyQT 和线程

发布于 2024-09-25 10:33:33 字数 200 浏览 4 评论 0原文

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

I am developing an application that uses multiple threads to gather data 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?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

醉城メ夜风 2024-10-02 10:33:34

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

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

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.

彼岸花ソ最美的依靠 2024-10-02 10:33:34

这是一个迟到的回复,但我想分享我的发现。这是来自 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_())

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_())
小矜持 2024-10-02 10:33:34

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

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.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文