Python 从PyQt GUI连接到串行
我写了一个程序来发送和接收串行数据,但我有一个问题,我想创建一个函数“connect()”或一个类,当我按下一个按钮时,该函数被执行,但是如果我在“MainWindow”类中创建这个函数,来自“TestThread”类的变量“ser”将无法初始化,你能帮助我吗Python 从PyQt GUI连接到串行,python,python-3.x,pyqt5,pyserial,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, pyqt
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()
与其使用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_())
我使用了上面重新设计的代码,因此它有一个
主窗口
,带有菜单栏
和状态栏
。我还添加了QSerialPortInfo类。此版本将查找活动端口并在状态栏上显示它们
我只在RPI4和Windows10上测试过这个
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_())
导入系统
从PyQt5导入QtCore、QtWidgets、QtSerialPort
从PyQt5.qtwidts导入QApplication、QMainWindow、QWidget、QToolBar、QHBoxLayout、QAction、QStatusBar、QLineEdit、QPushButton、qtexedit、QVBoxLayout
从PyQt5.QtCore导入Qt,pyqtSignal
从PyQt5.QtSerialPort导入QSerialPortInfo
类AddComport(QMainWindow):
porttnavn=pyqtSignal(str)
定义初始化(自、父、菜单):
super()。\uuuu init\uuuu(父级)
menuComporte=menu.addMenu(“Comporte”)
info_list=QSerialPortInfo()
serial\u list=info\u list.availableport()
serial_ports=[port.portName()表示串行_列表中的端口]
如果(len(串行_端口)>0):
antalporte=len(串行端口)
antal=0
而安塔尔<安塔尔波特:
按钮动作=QAction(串行端口[antal],自身)
txt=串行端口[antal]
portinfo=QSerialPortInfo(txt)
buttoninfotxt=“Ingen informationer”
如果portinfo.hasProductIdentifier():
buttoninfotxt=(“产品规范=“+str(portinfo.vendoriIdentifier()))
如果portinfo.hasVendorIdentifier():
buttoninfotxt=buttoninfotxt+(“Fremstillers id=“+str(portinfo.productIdentifier()))
按钮动作=QAction(txt,自我)
button_action.setStatusIP(buttoninfotxt)
按钮\u action.triggered.connect(选中lambda,txt=txt:self.valgAfComportClick(txt))
menuComporte.addAction(按钮操作)
antal=antal+1
其他:
打印(“Ingen com porte fundet”)
def VALGAFCOMPORT单击(自身,端口):
self.porttnavn.emit(端口)
def关闭事件(自身、事件):
selv.close()
类主窗口(QMainWindow):
定义初始化(自):
超级(主窗口,自我)。\uuuu初始化
portname=“无”
self.setStatusBar(QStatusBar(self))
menu=self.menuBar()
comfinder=AddComport(自我,菜单)
comfinder.porttnavn.connect(self.valgAfComport)
self.setWindowTitle(“串口显示/发送”)
self.message_le=QLineEdit()
self.send\u btn=QPushButton(
text=“发送”,
单击=self.send
)
self.output_te=QTextEdit(readOnly=True)
self.button=QPushButton(
text=“连接”,
可检查=正确,
toggled=self.on\u切换
)
lay=QVBoxLayout(自身)
hlay=QHBoxLayout()
hlay.addWidget(self.message_le)
hlay.addWidget(self.send\u btn)
布局。添加布局(hlay)
lay.addWidget(自输出)
lay.addWidget(self.button)
widget=QWidget()
widget.setLayout(lay)
self.setCentralWidget(小部件)
self.serial=QtSerialPort.QSerialPort(
portname,
波特率=QtSerialPort.QSerialPort.Baud9600,
readyRead=self.receive)
@QtCore.pyqtSlot()
def接收(自我):
而self.serial.canReadLine()
text=self.serial.readLine().data().decode()
text=text.rstrip('\r\n')
self.output_te.append(文本)
@QtCore.pyqtSlot()
def发送(自我):
self.serial.write(self.message_.le.text().encode())
@QtCore.pyqtlot(bool)
def on_已切换(自检、已检查):
self.button.setText(“断开”如果选中,否则“连接”)
如果选中:
如果不是self.serial.isOpen():
self.serial.open(QtCore.QIODevice.ReadWrite)
如果不是self.serial.isOpen():
self.button.setChecked(False)
其他:
self.button.setChecked(False)
其他:
self.serial.close()
def valgAfComport(自身,nyport):
seropen=False
如果self.serial.isOpen():
seropen=True
self.serial.close()
self.serial.setPortName(nyport)
如果是seropen:
self.serial.open(QtCore.QIODevice.ReadWrite)
如果不是self.serial.isOpen():
self.button.setChecked(False)
打印(nyport)
def关闭事件(自身、事件):
self.serial.close()
印刷品(“康波特卢克特”)
打印(comporttxt)
如果uuuu name uuuuuu='\uuuuuuu main\uuuuuuu':
app=qtwidts.QApplication(sys.argv)
w=主窗口()
w、 show()
sys.exit(app.exec_())
解释你自己better@eyllanesc好的,当我按下一个按钮时,我想连接到Arduino(打开串行),当我按下另一个按钮时关闭连接(关闭串行),但我不知道如何实现这一点非常感谢,我将使用您的代码,但为了我的和平,可以从“主窗口”的按钮连接到串行上课?同时,我的“TestThread”类运行良好。。你能给我举个例子吗?