PyQt5 front-end and python back-end
-
Hi I just created a simple Serial Terminal App. Its UI is designed using Qt Designer and imported in the project using UIC module. Just wanted to know that the way I used PyQt5 with Python is he correct one any comments and input are welcome. Since Qt uses signals and slots for communication used QThread subclass that will generate necessary signal which is captured by the Event Loop and since I did not find a way to send back response (like button press, text change etc) used class instance and passed that to the respective member for further processing.
It is working well for now. But, I need someone to look into the code and provide inputs on the same.
from PyQt5 import QtWidgets from gui import UI import sys if __name__ == '__main__': app = QtWidgets.QApplication(sys.argv) window = UI() window.show() sys.exit(app.exec_())
serial_control.py
from PyQt5.QtCore import QThread from PyQt5 import QtCore import serial import serial.tools.list_ports import time class SerialControl(QThread): status = QtCore.pyqtSignal(bool) received = QtCore.pyqtSignal(str) def __init__(self): super().__init__() self.VID = 0x2341 self.PID = 0x3d self.serial = None self.input = "" self.output = "" self.connected = False def find_port(self): for port in serial.tools.list_ports.comports(): if (port.vid == self.VID) and (port.pid == self.PID): print("Port: ", port.device) return port.device return None def run(self): while True: if not self.connected: port = self.find_port() if port: try: self.serial = serial.Serial(port, 115200, timeout=0.25) if self.serial: self.connected = True print("Connected") self.status.emit(True) except serial.SerialException: pass elif self.connected: try: if not self.serial.is_open: self.serial.open() except AttributeError: pass try: if self.serial.in_waiting: self.input = self.serial.readline().decode("utf-8") print("Received: ", self.input) self.received.emit(self.input) elif self.output: time.sleep(0.25) self.serial.write(self.output.encode()) print("Sent: ", self.output) self.output = "" except OSError: print("Disconnected") self.connected = False self.status.emit(False) time.sleep(0.25)
from PyQt5 import QtWidgets, uic from serial_control import SerialControl class UI(QtWidgets.QMainWindow): def __init__(self): super(UI, self).__init__() self.terminal = SerialControl() self.setup_ui() def setup_ui(self): uic.loadUi('ui.ui', self) self.btn_send.clicked.connect(self.send) self.start_terminal() def start_terminal(self): self.terminal.status.connect(self.control_button) self.terminal.received.connect(self.receive) self.terminal.start() def control_button(self, state): self.btn_send.setEnabled(state) def send(self): self.terminal.output = self.lineEdit.text() self.lineEdit.setText('') def receive(self, msg): self.textEdit.setText(msg)
ui.ui
<?xml version="1.0" encoding="UTF-8"?> <ui version="4.0"> <class>MainWindow</class> <widget class="QMainWindow" name="MainWindow"> <property name="geometry"> <rect> <x>0</x> <y>0</y> <width>715</width> <height>510</height> </rect> </property> <property name="windowTitle"> <string>Serial Terminal</string> </property> <widget class="QWidget" name="centralwidget"> <layout class="QVBoxLayout" name="verticalLayout_3"> <item> <layout class="QVBoxLayout" name="verticalLayout" stretch="1,0,5"> <item> <widget class="QWidget" name="horizontalWidget" native="true"> <property name="sizePolicy"> <sizepolicy hsizetype="Preferred" vsizetype="Fixed"> <horstretch>0</horstretch> <verstretch>0</verstretch> </sizepolicy> </property> <layout class="QHBoxLayout" name="horizontalLayout" stretch="1,0,0"> <property name="spacing"> <number>6</number> </property> <property name="leftMargin"> <number>5</number> </property> <property name="topMargin"> <number>5</number> </property> <property name="rightMargin"> <number>5</number> </property> <property name="bottomMargin"> <number>5</number> </property> <item> <widget class="QLineEdit" name="lineEdit"/> </item> <item> <spacer name="horizontalSpacer"> <property name="orientation"> <enum>Qt::Horizontal</enum> </property> <property name="sizeHint" stdset="0"> <size> <width>40</width> <height>20</height> </size> </property> </spacer> </item> <item> <widget class="QPushButton" name="btn_send"> <property name="enabled"> <bool>false</bool> </property> <property name="text"> <string>Send</string> </property> </widget> </item> </layout> </widget> </item> <item> <spacer name="verticalSpacer"> <property name="orientation"> <enum>Qt::Vertical</enum> </property> <property name="sizeType"> <enum>QSizePolicy::Fixed</enum> </property> <property name="sizeHint" stdset="0"> <size> <width>20</width> <height>10</height> </size> </property> </spacer> </item> <item> <widget class="QGroupBox" name="groupBox"> <property name="title"> <string>Received</string> </property> <layout class="QVBoxLayout" name="verticalLayout_2"> <property name="spacing"> <number>0</number> </property> <property name="leftMargin"> <number>0</number> </property> <property name="topMargin"> <number>0</number> </property> <property name="rightMargin"> <number>0</number> </property> <property name="bottomMargin"> <number>0</number> </property> <item> <widget class="QTextEdit" name="textEdit"/> </item> </layout> </widget> </item> </layout> </item> </layout> </widget> <widget class="QStatusBar" name="statusbar"/> </widget> <resources/> <connections/> </ui>
-
Hi,
Before analyzing your code deeper, why not use Qt's QSerialPort class that is asynchronous rather than adding threading to the mix ?
-
You should:
- provide a clean way to quit your thread
- use a cleaner setup/tear down for the opening and closing of your device
- why all these sleep call ?