Using a QThread in PyQT for serial communication (w. pyserial)

眉间皱痕 提交于 2019-12-21 05:05:19

问题


I am pretty much a beginner when it comes to GUI programming. I am using QT in combination with python bindings (PyQT4).

What I am trying to do:

  • Setting up a QThread to read from & write to a Serial Port with pyserial.
  • The main application should be able to emit new serial data via a signal to the running QThread. and receive serial data from the QThread with a signal.

I started my own test implementation based on this code (Link). Prior to this I read the basics about QThreads and tried to understand how they are intended to be used. The following test code is what I have come up with. I m sorry, I tried to keep it minmal, but it is still 75 lines of code:

from PyQt4 import QtCore, QtGui
import time
import sys

class SerialData(QtCore.QObject):
    def __init__(self, message):
        super(SerialData, self).__init__()
        self.__m = message
    def getMsg(self):
        return self.__m

class SerialCon(QtCore.QObject):

    finished = QtCore.pyqtSignal()
    received = QtCore.pyqtSignal(SerialData)

    def init(self):
       super(SerialCon, self).__init__()
       # TODO setup serial connection:
       # setting up a timer to check periodically for new received serial data
       self.timer = QtCore.QTimer()
       self.timer.setInterval(400)
       self.timer.timeout.connect(self.readData)
       self.timer.start(200)
       # self.finished.emit()

    def readData(self):
       self.received.emit(SerialData("New serial data!"))
       print "-> serial.readLine() ..."

    @QtCore.pyqtSlot(SerialData)
    def writeData(self, data):
       print "-> serial.write(), ", data.getMsg()


class MyGui(QtGui.QWidget):
    serialWrite = QtCore.pyqtSignal(SerialData)

    def __init__(self):
       super(MyGui, self).__init__()
       self.initUI()

    def initUI(self):
       bSend = QtGui.QPushButton("Send",self)
       bSend.clicked.connect(self.sendData)
       self.show()

    @QtCore.pyqtSlot(SerialData)
    def updateData(self, data):
        print "Gui:", data.getMsg()

    def sendData(self, pressed):
       data = SerialData("Send me!")
       self.serialWrite.emit(data)

def usingMoveToThread():
    app = QtGui.QApplication(sys.argv)
    guui = MyGui()

    thread = QtCore.QThread()
    serialc = SerialCon()
    serialc.moveToThread(thread)

    # connecting signals to slots
    serialc.finished.connect(thread.quit)
    guui.serialWrite.connect(serialc.writeData)
    serialc.received.connect(guui.updateData)
    thread.started.connect(serialc.init)
    thread.finished.connect(app.exit)
    thread.start()

    sys.exit(app.exec_())

if __name__ == "__main__":
    usingMoveToThread()

My Problems:

  • In test code the signal emitted from the SerialCon object (which has been moved to the QThread) seems to be not received by the corresponding slot (in MyGui, updateData)

  • Sooner or later the running test code always causes a Segmentation fault (core dumped). Which makes me believe that I missed some important bits.

What could cause this?

Maybe I m taking a completely wrong approach? - so if you have a better idea how to achieve this, I d be very grateful to hear about it!

Thanks a lot!


回答1:


At first I was only focussing on the new way, how QThreads should be used since QT4 (Link), by creating a QObject, and then invoking moveToThread(), pretty much like in my first code sample (at least thats how I understood it). However I just could not figure out, why I was not able to pass signals from the QThread to the main application.

As I really needed a fast solution to my problem, I desperately tried varius things. Here is some second code, that does seem to work the way I wanted:

from PyQt4 import QtCore, QtGui
import time
import sys
import math


class SerialCon(QtCore.QThread):

    received = QtCore.pyqtSignal(object)

    def __init__(self, parent=None):
        QtCore.QThread.__init__(self)
        # specify thread context for signals and slots:
        # test: comment following line, and run again
        self.moveToThread(self)
        # timer:
        self.timer = QtCore.QTimer()
        self.timer.moveToThread(self)
        self.timer.setInterval(800)
        self.timer.timeout.connect(self.readData)

    def run(self):
        self.timer.start()
        #start eventloop
        self.exec_()

    def readData(self):
        # keeping the thread busy
        # figure out if the GUI remains responsive (should be running on a different thread)
        result = []
        for i in range(1,1000000):
            result.append(math.pow(i,0.2)*math.pow(i,0.1)*math.pow(i,0.3))
        #
        self.received.emit("New serial data!")

    @QtCore.pyqtSlot(object)
    def writeData(self, data):
       #print(self.currentThreadId())
       print(data)

class MyGui(QtGui.QWidget):
    serialWrite = QtCore.pyqtSignal(object)

    def __init__(self, app, parent=None):
       self.app = app
       super(MyGui, self).__init__(parent)
       self.initUI()

    def initUI(self):
       self.bSend = QtGui.QPushButton("Send",self)
       self.bSend.clicked.connect(self.sendData)
       self.show()
    def closeEvent(self, event):
        print("Close.")
        self.serialc.quit();

    @QtCore.pyqtSlot(object)
    def updateData(self, data):
        print(data)

    def sendData(self, pressed):
       self.serialWrite.emit("Send Me! Please?")

    def usingMoveToThread(self):
        self.serialc = SerialCon()
        # binding signals:
        self.serialc.received.connect(self.updateData)
        self.serialWrite.connect(self.serialc.writeData)
        # start thread
        self.serialc.start()

if __name__ == "__main__":
    app = QtGui.QApplication(sys.argv)
    guui = MyGui(app)
    guui.usingMoveToThread()
    sys.exit(app.exec_())

I consider it a workaround for now, but it does not really answer the question for me. Plus, as mentioned in the previously linked QT blog entry, it is not really the intended way to use the QThread. So I am still wondering how to get the first code in my question to work as expected. If you have some ideas about what is wrong with my first code, please let my know!



来源:https://stackoverflow.com/questions/18378536/using-a-qthread-in-pyqt-for-serial-communication-w-pyserial

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!