在 PyQT 中使用 QThread 进行串行通信(w. pyserial) [英] Using a QThread in PyQT for serial communication (w. pyserial)

查看:60
本文介绍了在 PyQT 中使用 QThread 进行串行通信(w. pyserial)的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

在 GUI 编程方面,我几乎是初学者.我将 QT 与 Python 绑定 (PyQT4) 结合使用.

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

我想做什么:

  • 设置一个 QThread 来读取 &写入串行端口pyserial.
  • 主应用程序应该能够通过向正在运行的 QThread 发出信号.并从串口接收数据QThread 带有信号.
  • 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.

我基于此代码(链接)开始了我自己的测试实现.在此之前,我阅读了有关 QThread 的基础知识,并试图了解它们的用途.下面的测试代码是我想出来的.对不起,我尽量保持最小,但它仍然是 75 行代码:

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()

我的问题:

  • 在测试代码中,从 SerialCon 对象(它有已移至 QThread) 似乎未收到对应的槽(在MyGui, updateData)

  • 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!

非常感谢!

推荐答案

一开始我只关注新的方式,从 QT4 开始应该如何使用 QThreads(链接),通过创建一个 QObject,然后调用 moveToThread(),就像在我的第一个代码示例中一样(至少我是这么理解的).但是我就是想不通,为什么我不能从QThread 到主应用程序.

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_())

我现在认为这是一种解决方法,但它并没有真正回答我的问题.另外,如之前链接的 QT 博客条目所述,它并不是使用 QThread 的真正预期方式.所以我仍然想知道如何让我的问题中的第一个代码按预期工作.如果您对我的第一个代码有什么问题有一些想法,请告诉我!

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!

这篇关于在 PyQT 中使用 QThread 进行串行通信(w. pyserial)的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆