PyQT实时显示串口数据抛出最大递归深度超出QtCore.QTimer.singleShot()异常 [英] PyQT real time display of serial port data throwing maximum recursion depth exceeded exception on QtCore.QTimer.singleShot()

查看:51
本文介绍了PyQT实时显示串口数据抛出最大递归深度超出QtCore.QTimer.singleShot()异常的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我的应用场景:

从串行端口读取连续数据(实时)并显示在 PyQt GUI 上,并将数据存储在 csv 文件中.

Read continues data (realtime) from serial port and display on PyQt GUI and also store data in csv file.

我尝试使用 While 循环.<-- 由于呼叫阻塞而不起作用.

I have tried to use While loop. <-- which does not work due to the call blocking.

所以,我在二手时尝试过 QtCore.QTimer.singleShot(1, methodname).哪个抛出递归异常.

So, on second hand I have tried QtCore.QTimer.singleShot(1, methodname). Which throwing recursion exception.

我的代码:

# -*- coding: utf-8 -*-

# Form implementation generated from reading ui file 'D:\TUK\Master Thesis\ML\Lable_Data.ui'
#
# Created by: PyQt5 UI code generator 5.11.2
#
# WARNING! All changes made in this file will be lost!

from PyQt5 import QtCore, QtGui, QtWidgets
import traceback
import os
import sys
import serial
import atexit
import time

write_path = "recording_folder1/"

port = "COM6"  # COM for windows, it changes when we use unix system
#ser = serial.Serial(port, 115200, timeout=None)

class Ui_MainWindow(object):
    def setupUi(self, MainWindow):
        MainWindow.setObjectName("MainWindow")
        MainWindow.resize(850, 568)
        icon = QtGui.QIcon()
        icon.addPixmap(QtGui.QPixmap("C:/Users/HackoMan/Google Drive/MasterThesis/Code/QtDesigner/Icon/research4-1.png"), QtGui.QIcon.Normal, QtGui.QIcon.Off)
        MainWindow.setWindowIcon(icon)
        self.centralwidget = QtWidgets.QWidget(MainWindow)
        self.centralwidget.setObjectName("centralwidget")
        self.gridLayout = QtWidgets.QGridLayout(self.centralwidget)
        self.gridLayout.setObjectName("gridLayout")
        self.DataLabelingTabObj = QtWidgets.QTabWidget(self.centralwidget)
        self.DataLabelingTabObj.setObjectName("DataLabelingTabObj")
        self.tab = QtWidgets.QWidget()
        self.tab.setObjectName("tab")
        self.formLayoutWidget = QtWidgets.QWidget(self.tab)
        self.formLayoutWidget.setGeometry(QtCore.QRect(10, 10, 811, 481))
        self.formLayoutWidget.setObjectName("formLayoutWidget")
        self.gridLayout_2 = QtWidgets.QGridLayout(self.formLayoutWidget)
        self.gridLayout_2.setSizeConstraint(QtWidgets.QLayout.SetMaximumSize)
        self.gridLayout_2.setContentsMargins(0, 0, 0, 0)
        self.gridLayout_2.setObjectName("gridLayout_2")
        self.horizontalLayout = QtWidgets.QHBoxLayout()
        self.horizontalLayout.setObjectName("horizontalLayout")
        self.startCaptureBtn = QtWidgets.QPushButton(self.formLayoutWidget)
        self.startCaptureBtn.setObjectName("startCaptureBtn")
        self.horizontalLayout.addWidget(self.startCaptureBtn)
        self.stopCaptureBtn = QtWidgets.QPushButton(self.formLayoutWidget)
        self.stopCaptureBtn.setEnabled(False)
        self.stopCaptureBtn.setObjectName("stopCaptureBtn")
        self.horizontalLayout.addWidget(self.stopCaptureBtn)
        self.gridLayout_2.addLayout(self.horizontalLayout, 3, 1, 1, 1)
        self.fileNameLabel = QtWidgets.QLabel(self.formLayoutWidget)
        self.fileNameLabel.setObjectName("fileNameLabel")
        self.gridLayout_2.addWidget(self.fileNameLabel, 0, 0, 1, 1)
        self.fileNameLineEdit = QtWidgets.QLineEdit(self.formLayoutWidget)
        self.fileNameLineEdit.setObjectName("fileNameLineEdit")
        self.gridLayout_2.addWidget(self.fileNameLineEdit, 0, 1, 1, 1)
        self.label = QtWidgets.QLabel(self.formLayoutWidget)
        self.label.setObjectName("label")
        self.gridLayout_2.addWidget(self.label, 2, 0, 1, 1)
        self.classLabelLabel = QtWidgets.QLabel(self.formLayoutWidget)
        self.classLabelLabel.setObjectName("classLabelLabel")
        self.gridLayout_2.addWidget(self.classLabelLabel, 1, 0, 1, 1)
        self.classLabelLineEdit = QtWidgets.QLineEdit(self.formLayoutWidget)
        self.classLabelLineEdit.setObjectName("classLabelLineEdit")
        self.gridLayout_2.addWidget(self.classLabelLineEdit, 1, 1, 1, 1)
        self.sensorTextEdit = QtWidgets.QTextEdit(self.formLayoutWidget)
        self.sensorTextEdit.setReadOnly(True)
        self.sensorTextEdit.setObjectName("sensorTextEdit")
        self.gridLayout_2.addWidget(self.sensorTextEdit, 2, 1, 1, 1)
        self.label_2 = QtWidgets.QLabel(self.formLayoutWidget)
        self.label_2.setObjectName("label_2")
        self.gridLayout_2.addWidget(self.label_2, 3, 0, 1, 1)
        self.horizontalLayout_8 = QtWidgets.QHBoxLayout()
        self.horizontalLayout_8.setObjectName("horizontalLayout_8")
        self.resetBtn = QtWidgets.QPushButton(self.formLayoutWidget)
        self.resetBtn.setObjectName("resetBtn")
        self.horizontalLayout_8.addWidget(self.resetBtn)
        self.closeBtn = QtWidgets.QPushButton(self.formLayoutWidget)
        self.closeBtn.setObjectName("closeBtn")
        self.horizontalLayout_8.addWidget(self.closeBtn)
        self.gridLayout_2.addLayout(self.horizontalLayout_8, 4, 1, 1, 1)
        self.DataLabelingTabObj.addTab(self.tab, "")
        self.tab_2 = QtWidgets.QWidget()
        self.tab_2.setObjectName("tab_2")
        self.DataLabelingTabObj.addTab(self.tab_2, "")
        self.gridLayout.addWidget(self.DataLabelingTabObj, 0, 1, 1, 1)
        MainWindow.setCentralWidget(self.centralwidget)
        self.statusbar = QtWidgets.QStatusBar(MainWindow)
        self.statusbar.setObjectName("statusbar")
        MainWindow.setStatusBar(self.statusbar)

        self.retranslateUi(MainWindow)
        self.DataLabelingTabObj.setCurrentIndex(0)
        QtCore.QMetaObject.connectSlotsByName(MainWindow)

        self.addButtonOperations()
        self.addFiledsValidators()

    def retranslateUi(self, MainWindow):
        _translate = QtCore.QCoreApplication.translate
        MainWindow.setWindowTitle(_translate("MainWindow", "Data Collection"))
        self.startCaptureBtn.setToolTip(_translate("MainWindow", "click to capture the sensor data"))
        self.startCaptureBtn.setWhatsThis(_translate("MainWindow", "click to capture the sensor data"))
        self.startCaptureBtn.setText(_translate("MainWindow", "Start"))
        self.stopCaptureBtn.setText(_translate("MainWindow", "Stop"))
        self.fileNameLabel.setText(_translate("MainWindow", "FileName"))
        self.label.setText(_translate("MainWindow", "Sensor Data"))
        self.classLabelLabel.setText(_translate("MainWindow", "ClassLabel"))
        self.label_2.setText(_translate("MainWindow", "Capture Sensor Data"))
        self.resetBtn.setText(_translate("MainWindow", "Reset"))
        self.closeBtn.setText(_translate("MainWindow", "Close"))
        self.DataLabelingTabObj.setTabText(self.DataLabelingTabObj.indexOf(self.tab), _translate("MainWindow", "Data labeling"))
        self.DataLabelingTabObj.setTabText(self.DataLabelingTabObj.indexOf(self.tab_2), _translate("MainWindow", "Classifier"))

    def addButtonOperations(self):
        self.closeBtn.clicked.connect(self.closeWindow)
        self.resetBtn.clicked.connect(self.resetFields)
        self.startCaptureBtn.clicked.connect(self.startCaptureBtnPressedEvent)
        self.stopCaptureBtn.clicked.connect(self.stopCaptureSensorData)

    def addFiledsValidators(self):

        regexp = QtCore.QRegExp('[a-zA-Z0-9_ -]+')
        validator = QtGui.QRegExpValidator(regexp)

        self.fileNameLineEdit.setValidator(validator)
        self.classLabelLineEdit.setValidator(validator)


    def captureSensorData(self, file):

        current_label = self.classLabelLineEdit.text()

        # new_line = ser.readline().decode('utf-8').rstrip()
        new_line = "test1, Test2, Test3"
        new_line = new_line + ',' + current_label + '\n'

        file.write(new_line)
        file.flush()

        self.sensorTextEdit.append(new_line)
        self.sensorTextEdit.repaint()

        if not self.startCaptureBtn.isEnabled():
            QtCore.QTimer.singleShot(1, self.captureSensorData(file))
        else:
            file.close()

    def startCaptureBtnPressedEvent(self):
        try:
            if(self.isValidFields()):
                # capture the sensor data
                print("#capturing the sensor data")
                self.startCaptureBtn.setEnabled(False)
                self.stopCaptureBtn.setEnabled(True)

                self.startCaptureBtn.repaint()
                self.stopCaptureBtn.repaint()

                file = self.openFileForWriting()  # Create/Open file for saving sensor data

                if not self.startCaptureBtn.isEnabled():
                    QtCore.QTimer.singleShot(1, self.captureSensorData(file))


            else:
                # throw error message
                print("#throw error message")
                msgBox = QtWidgets.QMessageBox()
                msgBox.setText("Please fill the required fields ")
                msgBox.setWindowTitle("Warning !! ")
                msgBox.setIcon(QtWidgets.QMessageBox.Warning)
                msgBox.exec()
        except:
            traceback.print_exc()


    def openFileForWriting(self):
        os.makedirs(os.path.dirname(write_path), exist_ok=True)
        file_name = self.fileNameLineEdit.text()
        file_name  = write_path + file_name + ".csv"
        file = open(file_name, 'a')
        return file

    def stopCaptureSensorData(self):
        # stop capture the sensor data
        print("# stop capturing the sensor data")
        self.startCaptureBtn.setEnabled(True)
        self.stopCaptureBtn.setEnabled(False)

        self.startCaptureBtn.repaint()
        self.stopCaptureBtn.repaint()



    def isValidFields(self):
        if(self.fileNameLineEdit.text().__len__()<=0 or self.classLabelLineEdit.text().__len__()<=0):
            return False
        else:
            return True

    def resetFields(self):
        self.fileNameLineEdit.clear()
        self.classLabelLineEdit.clear()
        self.sensorTextEdit.clear()

    def closeWindow(self):
        QtCore.QCoreApplication.instance().quit()


    def releaseResource(self):
        print("Release Resources !!! ")
        #if ser.isOpen():
        #    ser.close()

if __name__ == "__main__":
    app = QtWidgets.QApplication(sys.argv)
    MainWindow = QtWidgets.QMainWindow()
    ui = Ui_MainWindow()
    ui.setupUi(MainWindow)
    MainWindow.show()
    atexit.register(ui.releaseResource)
    sys.exit(app.exec_())

请让我知道您是否正在执行类似的操作,例如读取数据库数据并在 GUI 上显示...等,或者是否有人在 pyqt 中找到了解决方案.

Please let me know if you doing something similar operation such as reading database data and displaying on GUI... etc or if anyone had found solution in pyqt.

错误信息:

推荐答案

根据我上面没有任何参数尝试过的评论之一,问题已解决.使用 captureSensorData 而不是 captureSensorData(file)

As per one of the comment I have tried above with out any parameter and the issue resolved. use captureSensorData instead of captureSensorData(file)

解决方案:

# -*- coding: utf-8 -*-

# Form implementation generated from reading ui file 'D:\TUK\Master Thesis\ML\Lable_Data.ui'
#
# Created by: PyQt5 UI code generator 5.11.2
#
# WARNING! All changes made in this file will be lost!

from PyQt5 import QtCore, QtGui, QtWidgets
import traceback
import os
import sys
import serial
import atexit


write_path = "recording_folder1/"

port = "COM6"  # COM for windows, it changes when we use unix system
ser = serial.Serial(port, 115200, timeout=None)
file = None

class Ui_MainWindow(object):
    def setupUi(self, MainWindow):
        MainWindow.setObjectName("MainWindow")
        MainWindow.resize(850, 568)
        icon = QtGui.QIcon()
        icon.addPixmap(QtGui.QPixmap("C:/Users/HackoMan/Google Drive/MasterThesis/Code/QtDesigner/Icon/research4-1.png"), QtGui.QIcon.Normal, QtGui.QIcon.Off)
        MainWindow.setWindowIcon(icon)
        self.centralwidget = QtWidgets.QWidget(MainWindow)
        self.centralwidget.setObjectName("centralwidget")
        self.gridLayout = QtWidgets.QGridLayout(self.centralwidget)
        self.gridLayout.setObjectName("gridLayout")
        self.DataLabelingTabObj = QtWidgets.QTabWidget(self.centralwidget)
        self.DataLabelingTabObj.setObjectName("DataLabelingTabObj")
        self.tab = QtWidgets.QWidget()
        self.tab.setObjectName("tab")
        self.formLayoutWidget = QtWidgets.QWidget(self.tab)
        self.formLayoutWidget.setGeometry(QtCore.QRect(10, 10, 811, 481))
        self.formLayoutWidget.setObjectName("formLayoutWidget")
        self.gridLayout_2 = QtWidgets.QGridLayout(self.formLayoutWidget)
        self.gridLayout_2.setSizeConstraint(QtWidgets.QLayout.SetMaximumSize)
        self.gridLayout_2.setContentsMargins(0, 0, 0, 0)
        self.gridLayout_2.setObjectName("gridLayout_2")
        self.horizontalLayout = QtWidgets.QHBoxLayout()
        self.horizontalLayout.setObjectName("horizontalLayout")
        self.startCaptureBtn = QtWidgets.QPushButton(self.formLayoutWidget)
        self.startCaptureBtn.setObjectName("startCaptureBtn")
        self.horizontalLayout.addWidget(self.startCaptureBtn)
        self.stopCaptureBtn = QtWidgets.QPushButton(self.formLayoutWidget)
        self.stopCaptureBtn.setEnabled(False)
        self.stopCaptureBtn.setObjectName("stopCaptureBtn")
        self.horizontalLayout.addWidget(self.stopCaptureBtn)
        self.gridLayout_2.addLayout(self.horizontalLayout, 3, 1, 1, 1)
        self.fileNameLabel = QtWidgets.QLabel(self.formLayoutWidget)
        self.fileNameLabel.setObjectName("fileNameLabel")
        self.gridLayout_2.addWidget(self.fileNameLabel, 0, 0, 1, 1)
        self.fileNameLineEdit = QtWidgets.QLineEdit(self.formLayoutWidget)
        self.fileNameLineEdit.setObjectName("fileNameLineEdit")
        self.gridLayout_2.addWidget(self.fileNameLineEdit, 0, 1, 1, 1)
        self.label = QtWidgets.QLabel(self.formLayoutWidget)
        self.label.setObjectName("label")
        self.gridLayout_2.addWidget(self.label, 2, 0, 1, 1)
        self.classLabelLabel = QtWidgets.QLabel(self.formLayoutWidget)
        self.classLabelLabel.setObjectName("classLabelLabel")
        self.gridLayout_2.addWidget(self.classLabelLabel, 1, 0, 1, 1)
        self.classLabelLineEdit = QtWidgets.QLineEdit(self.formLayoutWidget)
        self.classLabelLineEdit.setObjectName("classLabelLineEdit")
        self.gridLayout_2.addWidget(self.classLabelLineEdit, 1, 1, 1, 1)
        self.sensorTextEdit = QtWidgets.QTextEdit(self.formLayoutWidget)
        self.sensorTextEdit.setReadOnly(True)
        self.sensorTextEdit.setObjectName("sensorTextEdit")
        self.gridLayout_2.addWidget(self.sensorTextEdit, 2, 1, 1, 1)
        self.label_2 = QtWidgets.QLabel(self.formLayoutWidget)
        self.label_2.setObjectName("label_2")
        self.gridLayout_2.addWidget(self.label_2, 3, 0, 1, 1)
        self.horizontalLayout_8 = QtWidgets.QHBoxLayout()
        self.horizontalLayout_8.setObjectName("horizontalLayout_8")
        self.resetBtn = QtWidgets.QPushButton(self.formLayoutWidget)
        self.resetBtn.setObjectName("resetBtn")
        self.horizontalLayout_8.addWidget(self.resetBtn)
        self.closeBtn = QtWidgets.QPushButton(self.formLayoutWidget)
        self.closeBtn.setObjectName("closeBtn")
        self.horizontalLayout_8.addWidget(self.closeBtn)
        self.gridLayout_2.addLayout(self.horizontalLayout_8, 4, 1, 1, 1)
        self.DataLabelingTabObj.addTab(self.tab, "")
        self.tab_2 = QtWidgets.QWidget()
        self.tab_2.setObjectName("tab_2")
        self.DataLabelingTabObj.addTab(self.tab_2, "")
        self.gridLayout.addWidget(self.DataLabelingTabObj, 0, 1, 1, 1)
        MainWindow.setCentralWidget(self.centralwidget)
        self.statusbar = QtWidgets.QStatusBar(MainWindow)
        self.statusbar.setObjectName("statusbar")
        MainWindow.setStatusBar(self.statusbar)

        self.retranslateUi(MainWindow)
        self.DataLabelingTabObj.setCurrentIndex(0)
        QtCore.QMetaObject.connectSlotsByName(MainWindow)

        self.addButtonOperations()
        self.addFiledsValidators()

    def retranslateUi(self, MainWindow):
        _translate = QtCore.QCoreApplication.translate
        MainWindow.setWindowTitle(_translate("MainWindow", "Data Collection"))
        self.startCaptureBtn.setToolTip(_translate("MainWindow", "click to capture the sensor data"))
        self.startCaptureBtn.setWhatsThis(_translate("MainWindow", "click to capture the sensor data"))
        self.startCaptureBtn.setText(_translate("MainWindow", "Start"))
        self.stopCaptureBtn.setText(_translate("MainWindow", "Stop"))
        self.fileNameLabel.setText(_translate("MainWindow", "FileName"))
        self.label.setText(_translate("MainWindow", "Sensor Data"))
        self.classLabelLabel.setText(_translate("MainWindow", "ClassLabel"))
        self.label_2.setText(_translate("MainWindow", "Capture Sensor Data"))
        self.resetBtn.setText(_translate("MainWindow", "Reset"))
        self.closeBtn.setText(_translate("MainWindow", "Close"))
        self.DataLabelingTabObj.setTabText(self.DataLabelingTabObj.indexOf(self.tab), _translate("MainWindow", "Data labeling"))
        self.DataLabelingTabObj.setTabText(self.DataLabelingTabObj.indexOf(self.tab_2), _translate("MainWindow", "Classifier"))

    def addButtonOperations(self):
        self.closeBtn.clicked.connect(self.closeWindow)
        self.resetBtn.clicked.connect(self.resetFields)
        self.startCaptureBtn.clicked.connect(self.startCaptureBtnPressedEvent)
        self.stopCaptureBtn.clicked.connect(self.stopCaptureSensorData)

    def addFiledsValidators(self):

        regexp = QtCore.QRegExp('[a-zA-Z0-9_ -]+')
        validator = QtGui.QRegExpValidator(regexp)

        self.fileNameLineEdit.setValidator(validator)
        self.classLabelLineEdit.setValidator(validator)


    def captureSensorData(self):
        try:

            current_label = self.classLabelLineEdit.text()

            #new_line = ser.readline().decode('utf-8').rstrip()
            new_line = "test1, Test2, Test3"
            new_line = new_line + ',' + current_label + '\n'

            self.file.write(new_line)
            self.file.flush()

            self.sensorTextEdit.append(new_line)
            self.sensorTextEdit.repaint()

            if not self.startCaptureBtn.isEnabled():
                QtCore.QTimer.singleShot(1, self.captureSensorData)
            else:
                self.file.close()
        except:
            traceback.print_exc()

    def startCaptureBtnPressedEvent(self):
        try:
            if(self.isValidFields()):
                # capture the sensor data
                print("#capturing the sensor data")
                self.startCaptureBtn.setEnabled(False)
                self.stopCaptureBtn.setEnabled(True)

                self.startCaptureBtn.repaint()
                self.stopCaptureBtn.repaint()

                self.file = self.openFileForWriting()  # Create/Open file for saving sensor data

                if not self.startCaptureBtn.isEnabled():
                    QtCore.QTimer.singleShot(1, self.captureSensorData)


            else:
                # throw error message
                print("#throw error message")
                msgBox = QtWidgets.QMessageBox()
                msgBox.setText("Please fill the required fields ")
                msgBox.setWindowTitle("Warning !! ")
                msgBox.setIcon(QtWidgets.QMessageBox.Warning)
                msgBox.exec()
        except:
            traceback.print_exc()


    def openFileForWriting(self):
        os.makedirs(os.path.dirname(write_path), exist_ok=True)
        file_name = self.fileNameLineEdit.text()
        file_name  = write_path + file_name + ".csv"
        file = open(file_name, 'a')
        return file

    def stopCaptureSensorData(self):
        # stop capture the sensor data
        print("# stop capturing the sensor data")
        self.startCaptureBtn.setEnabled(True)
        self.stopCaptureBtn.setEnabled(False)

        self.startCaptureBtn.repaint()
        self.stopCaptureBtn.repaint()



    def isValidFields(self):
        if(self.fileNameLineEdit.text().__len__()<=0 or self.classLabelLineEdit.text().__len__()<=0):
            return False
        else:
            return True

    def resetFields(self):
        self.fileNameLineEdit.clear()
        self.classLabelLineEdit.clear()
        self.sensorTextEdit.clear()

    def closeWindow(self):
        QtCore.QCoreApplication.instance().quit()


    def releaseResource(self):
        print("Release Resources !!! ")
        if ser.isOpen():
            ser.close()

if __name__ == "__main__":
    app = QtWidgets.QApplication(sys.argv)
    MainWindow = QtWidgets.QMainWindow()
    ui = Ui_MainWindow()
    ui.setupUi(MainWindow)
    MainWindow.show()
    atexit.register(ui.releaseResource)
    sys.exit(app.exec_())

这篇关于PyQT实时显示串口数据抛出最大递归深度超出QtCore.QTimer.singleShot()异常的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

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