从PyQt GUI连接到串行

时间:2019-03-08 20:21:52

标签: python python-3.x pyqt5 pyserial

我编写了一个程序,用于从串行发送和接收数据,但是我有一个问题,我想创建一个函数“ connect()”或一个类,并且当我按下按钮时,该函数就会执行,但是如果我在“ MainWindow”类中创建此函数,则“ TestThread”类中的变量“ ser”未初始化,您能帮我吗?

import sys
import serial


from PyQt5.QtWidgets import QMainWindow, QApplication
from PyQt5.QtCore import QThread, pyqtSignal
from PyQt5.uic import loadUi


ser = serial.Serial('/dev/tty.usbmodem14201', 9600, timeout=1)

class TestThread(QThread):
    serialUpdate = pyqtSignal(str)
    def run(self):
        while ser.is_open:
            QThread.sleep(1)
            value = ser.readline().decode('ascii')
            self.serialUpdate.emit(value)
            ser.flush()

class MainWindow(QMainWindow):
    def __init__(self):
        super(MainWindow, self).__init__()
        loadUi('/Users/bogdanvesa/P2A_GUI/mainwindow.ui', self)
        self.thread = TestThread(self)
        self.thread.serialUpdate.connect(self.handleSerialUpdate)

        self.connect_btn.clicked.connect(self.connectSer)
        self.lcd_EBtn.clicked.connect(self.startThread)

    def startThread(self):
        self.thread.start()

    def handleSerialUpdate(self, value):
        print(value)
        self.lcd_lineEdit.setText(value)


def main():

    app = QApplication(sys.argv)
    form = MainWindow()
    form.show()
    sys.exit(app.exec_())

if __name__ == "__main__":
    main()

2 个答案:

答案 0 :(得分:1)

我使用了上面重新设计的代码,所以它有一个 mainwindow,一个 menubar 和一个 statusbar。我还添加了 QSerialPortInfo 类。此版本将查找活动端口并将其显示在状态栏上。

我只在 rpi 4 和 Windows 10 上测试过。

import sys

from PyQt5 import QtCore, QtWidgets, QtSerialPort 
from PyQt5.QtWidgets import QApplication, QMainWindow ,QWidget ,QToolBar ,QHBoxLayout, QAction ,QStatusBar ,QLineEdit ,QPushButton ,QTextEdit , QVBoxLayout 
from PyQt5.QtCore import Qt , pyqtSignal
from PyQt5.QtSerialPort import QSerialPortInfo

class AddComport(QMainWindow):
    porttnavn = pyqtSignal(str)

    def __init__(self, parent , menu):
        super().__init__(parent)

  
        menuComporte = menu.addMenu("Comporte")
    
        info_list = QSerialPortInfo()
        serial_list = info_list.availablePorts()
        serial_ports = [port.portName() for port in serial_list]
        if(len(serial_ports)> 0):
            antalporte = len(serial_ports)
            antal = 0
            while antal < antalporte:
                button_action = QAction(serial_ports[antal], self)
                txt = serial_ports[antal]
                portinfo = QSerialPortInfo(txt)
                buttoninfotxt = " Ingen informationer"
                if portinfo.hasProductIdentifier():
                    buttoninfotxt = ("Produkt specifikation = " + str(portinfo.vendorIdentifier()))
                if portinfo.hasVendorIdentifier():
                    buttoninfotxt =  buttoninfotxt + (" Fremstillers id = "+ str(portinfo.productIdentifier()))
                button_action = QAction( txt , self)
                button_action.setStatusTip( buttoninfotxt)
                button_action.triggered.connect(lambda checked, txt = txt: self.valgAfComportClick(txt))
                menuComporte.addAction(button_action)
                antal = antal +1
        else:
            Print("Ingen com porte fundet")

    def valgAfComportClick(self , port):
        self.porttnavn.emit(port)
   
    def closeEvent(self, event):
        selv.close()


class MainWindow(QMainWindow):  
    def __init__(self):
        super(MainWindow, self).__init__()

        portname = "None"
    
        self.setStatusBar(QStatusBar(self))
   
        menu = self.menuBar()
        comfinder = AddComport(self , menu)
        comfinder.porttnavn.connect(self.valgAfComport)

        self.setWindowTitle("Serial port display / send")
    
        self.message_le = QLineEdit()
        self.send_btn = QPushButton(
            text="Send",
            clicked=self.send
        )
    
        self.output_te = QTextEdit(readOnly=True)
        self.button = QPushButton(
            text="Connect", 
            checkable=True,
            toggled=self.on_toggled
        )
        lay = QVBoxLayout(self)
        hlay = QHBoxLayout()
        hlay.addWidget(self.message_le)
        hlay.addWidget(self.send_btn)
        lay.addLayout(hlay)
        lay.addWidget(self.output_te)
        lay.addWidget(self.button)
    
        widget = QWidget()
        widget.setLayout(lay)
        self.setCentralWidget(widget)

        self.serial = QtSerialPort.QSerialPort(
            portname,
            baudRate=QtSerialPort.QSerialPort.Baud9600,
            readyRead=self.receive)
   
           
    @QtCore.pyqtSlot()
    def receive(self):
        while self.serial.canReadLine():
            text = self.serial.readLine().data().decode()
            text = text.rstrip('\r\n')
            self.output_te.append(text)

    @QtCore.pyqtSlot()
    def send(self):
        self.serial.write(self.message_le.text().encode())

    @QtCore.pyqtSlot(bool)
    def on_toggled(self, checked):
        self.button.setText("Disconnect" if checked else "Connect")
        if checked:
            if not self.serial.isOpen():
                self.serial.open(QtCore.QIODevice.ReadWrite)
                if not self.serial.isOpen():
                    self.button.setChecked(False)
            else:
                self.button.setChecked(False)
        else:
            self.serial.close()
  
    def valgAfComport(self , nyport):
        seropen = False
        if self.serial.isOpen():
            seropen = True
            self.serial.close()   
        self.serial.setPortName(nyport)
        if seropen:
            self.serial.open(QtCore.QIODevice.ReadWrite)
            if not self.serial.isOpen():
                self.button.setChecked(False)
        
        print(nyport)
    
    def closeEvent(self, event):
        self.serial.close()
        print("Comport lukket")
        print(comporttxt)
    
if __name__ == '__main__':
    app = QtWidgets.QApplication(sys.argv)
    w = MainWindow()
    w.show()
    sys.exit(app.exec_())

答案 1 :(得分:0)

与其使用pySerial +线程,不如使用Qt事件循环中的QSerialPort

from PyQt5 import QtCore, QtWidgets, QtSerialPort

class Widget(QtWidgets.QWidget):
    def __init__(self, parent=None):
        super(Widget, self).__init__(parent)
        self.message_le = QtWidgets.QLineEdit()
        self.send_btn = QtWidgets.QPushButton(
            text="Send",
            clicked=self.send
        )
        self.output_te = QtWidgets.QTextEdit(readOnly=True)
        self.button = QtWidgets.QPushButton(
            text="Connect", 
            checkable=True,
            toggled=self.on_toggled
        )
        lay = QtWidgets.QVBoxLayout(self)
        hlay = QtWidgets.QHBoxLayout()
        hlay.addWidget(self.message_le)
        hlay.addWidget(self.send_btn)
        lay.addLayout(hlay)
        lay.addWidget(self.output_te)
        lay.addWidget(self.button)

        self.serial = QtSerialPort.QSerialPort(
            '/dev/tty.usbmodem14201',
            baudRate=QtSerialPort.QSerialPort.Baud9600,
            readyRead=self.receive
        )

    @QtCore.pyqtSlot()
    def receive(self):
        while self.serial.canReadLine():
            text = self.serial.readLine().data().decode()
            text = text.rstrip('\r\n')
            self.output_te.append(text)

    @QtCore.pyqtSlot()
    def send(self):
        self.serial.write(self.message_le.text().encode())

    @QtCore.pyqtSlot(bool)
    def on_toggled(self, checked):
        self.button.setText("Disconnect" if checked else "Connect")
        if checked:
            if not self.serial.isOpen():
                if not self.serial.open(QtCore.QIODevice.ReadWrite):
                    self.button.setChecked(False)
        else:
            self.serial.close()

if __name__ == '__main__':
    import sys
    app = QtWidgets.QApplication(sys.argv)
    w = Widget()
    w.show()
    sys.exit(app.exec_())