【问题标题】:cannot pass data between thread and Qt object in Python无法在 Python 中的线程和 Qt 对象之间传递数据
【发布时间】:2015-12-11 19:09:41
【问题描述】:

我创建了一个 GUI,我必须在其上传递来自串行 COM 端口的字符串数据。一个单独的线程正在处理串行数据,而 Qt 对象需要获取该数据并通过“setPlainText”方法显示它。它给出了一个错误(在我在 cmets 中标记的线上)是

“QObject:无法为不同线程中的父级创建子级。 (父线程为QTextDocument(0x3ebaa68),父线程为QThread(0x3dd5c58),当前线程为QThread(0x3fbd6a8)"

这是我的代码;

import sys
from PyQt4 import QtGui
from My_GUI_code import Ui_Dialog
import serial # import Serial Library
import threading
import time



test=""
arduinoData = serial.Serial('COM2', 9600) #

index=0
incoming_data=""
device_0_V=""


class Serial_read(threading.Thread):
    """
    Thread to read data coming from Arduino
    """
    def __init__(self):
        threading.Thread.__init__(self)

    def run(self):
        global incoming_data
        global device_0_V
        global test
        while 1:
           while (arduinoData.inWaiting()==0): #Wait here until there is data
             pass #do nothing
           incoming_data = arduinoData.readline() #read the line of text from the serial port
           if "V0" in incoming_data:
              index = incoming_data.index("V0=") 
              device_0_V=incoming_data[index+3:index+6]
              print device_0_V
           #print incoming_data,

class Editor(QtGui.QMainWindow, threading.Thread):

    def __init__(self):
        threading.Thread.__init__(self)
        global device_0_V
        super(Editor, self).__init__()
        self.ui=Ui_Dialog()

        #test=self.ui.Dev_1_V
        self.ui.setupUi(self)
        self.setWindowIcon(QtGui.QIcon('ICON.png')) 
        self.ui.Dev_1_V.setPlainText("anum")
        self.show()
        self.ui.Dev_1_ON.clicked.connect(self.handleButton)

    def run(self):
        global device_0_V
        while 1:
            self.ui.Dev_1_V.setPlainText(device_0_V)   #<<here it gives ERROR
            time.sleep(1)

    def handleButton(self):
        time = self.ui.time_dev_1.value()
        self.ui.Dev_1_V.setPlainText(device_0_V)
        print time

        #print ('Hello World')

def main():
    tx_socket_thread2 = Serial_read()
    tx_socket_thread2.start()
    app = QtGui.QApplication(sys.argv)
    ex = Editor()
    ex.start()
    sys.exit(app.exec_())


if __name__ == '__main__':
    main()

我在 Stackoverflow 中看到了一些相关问题,但我仍然无法理解这个概念,因为我是 Classes、Qt 和 OOP 方面的新手。我知道我在这里犯了一些基本错误......任何帮助将不胜感激。

【问题讨论】:

  • 你这里有 3 个线程,如果我理解,你只需要 2 个。尝试在编辑器类中删除与线程有关的所有内容。将您的 Editor.run() 重命名为 watch_device 或其他名称,并在 ex.start() 之后从 main() 调用它。只是建议,因为我实际上无法运行所有这些......
  • 我建议查看queue 模块。您可以从串行线程将项目放入队列中,并在编辑器线程中使用例程检查队列。

标签: python multithreading qt


【解决方案1】:

因此,在阅读了 Stack Overflow 中相关问题后,我设法实现了我想要的,这是代码;

import sys
from PyQt4 import QtGui, QtCore
from My_GUI_code import Ui_Dialog
import serial # import Serial Library
import threading
import time



test=""
arduinoData = serial.Serial('COM2', 9600) #

index=0
incoming_data=""
device_0_V=""


class Serial_read(threading.Thread):
    """
    Thread to read data coming from Arduino
    """
    def __init__(self):
        threading.Thread.__init__(self)

    def run(self):
        global incoming_data
        global device_0_V
        global test
        while 1:
           while (arduinoData.inWaiting()==0): #Wait here until there is data
             pass #do nothing
           incoming_data = arduinoData.readline() #read the line of text from the serial port
           if "V0" in incoming_data:
              index = incoming_data.index("V0=") 
              device_0_V=incoming_data[index+3:index+6]
              print device_0_V
           #print incoming_data,

class Editor(QtGui.QMainWindow):

    def __init__(self):
        #threading.Thread.__init__(self)
        global device_0_V
        super(Editor, self).__init__()
        self.ui=Ui_Dialog()

        #test=self.ui.Dev_1_V
        self.ui.setupUi(self)
        self.setWindowIcon(QtGui.QIcon('ICON.png')) 
        self.ui.Dev_1_V.setPlainText("anum")
        self.show()
        self.ui.Dev_1_ON.clicked.connect(self.handleButton)

        self.worker = Worker(self)  # an independent thread that will listen to a signal 'beep' and trigger a function self.update
        self.connect(self.worker, QtCore.SIGNAL('beep'), self.update) 
        self.worker.start()  # start the thread

    def update(self, Serial_data):
        # here, I am getting the Serial data via signaling 
        if "V0" in incoming_data:
              index = incoming_data.index("V0=") 
              device_0_V=incoming_data[index+3:index+7]
              self.ui.Dev_1_V.setPlainText(device_0_V)


    def handleButton(self):
        time = self.ui.time_dev_1.value()
        self.ui.Dev_1_V.setPlainText(device_0_V)
        print time

        #print ('Hello World')

class Worker(QtCore.QThread):
    def __init__(self, host_window):
        super(Worker, self).__init__()
        self.running = False

    def run(self):
        self.running = True
        global incoming_data    #kept the Serial data global
        global device_0_V
        while self.running:
              #sending 'beep' signal to the main Qt object, with string data 'incoming_data'
              self.emit(QtCore.SIGNAL('beep'), incoming_data) 
              time.sleep(0.1)

    def stop(self):
        self.running = False


def main():
    tx_socket_thread2 = Serial_read()
    tx_socket_thread2.start()

    app = QtGui.QApplication(sys.argv)
    ex = Editor()

    sys.exit(app.exec_())


if __name__ == '__main__':
    main()

在主 Qt 对象中,我创建了一个 QThread“Worker”,它使用串行数据向主 Qt 对象发送信号。每次有信号从工作线程到达时触发更新函数,然后进一步读取来自工作线程的数据。

得到this问题的帮助

感谢@Andy 和@SiHa 的参与

【讨论】:

    【解决方案2】:

    这是一个描述 Qt 对象是什么和不是线程安全的页面 -- http://doc.qt.io/qt-4.8/threads-reentrancy.html

    在大多数情况下,GUI 对象不是线程安全的,您应该避免从其他线程修改它们。

    从其他线程影响 GUI 的一种方法是使用信号和槽系统,只要传递的任何对象都是线程安全的,它就可以在线程之间安全使用。这通常意味着在辅助线程中创建一个线程安全的数据结构并将其与信号一起传递给主线程,然后主线程读取数据结构并更新 GUI。

    该设计模式的更高级版本是使用 2 路队列。一个队列由主线程填充,主线程创建处理队列中项目的工作线程。完成后,工作线程使用主线程处理的线程安全返回值填充另一个队列。当队列中有要处理的项目时,仍然使用信号和事件来通知主线程和工作线程。

    另外,除非绝对想直接管理线程,否则您可以使用QRunnableQThreadPool 来启动线程,而无需直接管理它们。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2011-04-24
      • 2014-10-12
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多