Using QThread in PyQT for Serial Communications (w. Pyserial)

I start a lot when it comes to GUI programming. I use QT in conjunction with python bindings (PyQT4).

What I'm trying to do:

  • Configuring QThread to read and write to the serial port using pyserial.
  • The main application should be able to release new serial data through a signal to launch QThread . and receive serial data from QThread with a signal.

I started my own test implementation based on this code ( Link ). Before that, I read the basics of QThread and tried to understand how they are intended to be used. The following test code is what I came up with. I'm sorry, I tried to keep it in minimal, but it still contains 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 the test code, the signal emitted by the SerialCon object (which has been moved to QThread ), apparently, the corresponding slot was not received (in MyGui , updateData )

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

What could be the reason for this?

Maybe I'm wrong? - therefore, if you have an idea how to achieve this, I will be very grateful for that!

Thanks a lot!

+5
source share
1 answer

At first, I only focused on the new way how QThreads should be used with QT4 ( Link ) by creating a QObject and then calling moveToThread() , which is very similar to my first code example (at least as I understood it). However, I simply could not understand why I could not pass the signals from QThread to the main application.

Since I really needed a quick solution to my problem, I desperately tried different things. Here is the second code that seems 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 find this a workaround, but it really doesn't answer me. Also, as mentioned earlier in the QT blog entry, this does not mean that you are using QThread . So I'm still wondering how to get the first code in my question to work as expected. If you have some ideas about what's wrong with my first code, let me know!

0
source

Source: https://habr.com/ru/post/1498356/


All Articles