不能在Python中的线程和Qt对象之间传递数据

时间:2015-12-11 19:09:41

标签: python multithreading qt

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

" QObject:无法为不同线程中的父级创建子级。 (Parent是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的新手。我知道我在这里做了一些基本的错误......任何帮助都将受到高度赞赏。

2 个答案:

答案 0 :(得分:1)

所以在对Stack溢出中的相关问题进行了一些阅读后,我已经设法实现了我想要的,继承人的代码;

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”,它使用Serial数据向主Qt对象发送信号。每次从工作线程到达信号时都会触发更新功能,然后进一步读取来自工作线程的数据。

this问题

获得帮助

感谢@Andy和@SiHa的参与

答案 1 :(得分:0)

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

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

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

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

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