i have a serial app, The Robot
class need to always receive serial message and then to do some thing, the Demo
gui need to interactive Robot
and get Robot.handle_readData
, if no data get, need to get again and again until had data. Now i had no idea how to solve this problem, need someone give me good idea.
from PyQt5.QtWidgets import *
from PyQt5.QtCore import *
from PyQt5.QtGui import *
from PyQt5.QtSerialPort import *
class Robot(QObject):
def __init__(self):
super().__init__()
self.serial = QSerialPort()
self.serial.setPortName('COM2')
self.serial.setBaudRate(QSerialPort.Baud115200)
self.serial.readyRead.connect(self.handle_readData)
self.serial.open(QIODevice.ReadWrite)
#background message auto process
def handle_readData(self):
data = self.serial.readAll()
self.do_something(data)
return data
def do_something(self, data):pass
class Demo(QDialog):
def __init__(self):
super().__init__()
layout = QHBoxLayout()
layout.setContentsMargins(0, 0, 0, 0)
self.search_bn = QPushButton('query', clicked=self.get_query_info)
layout.addStretch(1)
layout.addWidget(self.search_bn)
main_layout = QVBoxLayout()
main_layout.addLayout(layout)
main_layout.addWidget(QTextEdit('msg'))
self.setLayout(main_layout)
#robot object
self.robot = Robot()
#forground message process, pseudo code
def get_query_info(self, checked):
self.robot.serial.write('show version')
#how to get Robot.handle_readData data,
data = Robot.handle_readData() # need to get this data
#if data is None, need to get again and again until data have some meaningful msg.
do_someting(data)
self.robot.serial.write('show system info')
# how to get Robot.handle_readData data,
data = Robot.handle_readData() # need to get this data
# if data is None, need to get again and again until data have some meaningful msg.
do_someting1(data)
app = QApplication([])
demo = Demo()
demo.show()
app.exec()
Qt is designed to work asynchronously, and instead your possible implementation is made for synchronous logic. The solution for these cases is to transform the implementation and in this case for example with the help of flags.
On the other hand do not process the information where you receive the information, instead it emits a signal so that it can be used elsewhere.
from enum import Enum, auto
from PyQt5.QtCore import pyqtSignal, pyqtSlot, QIODevice, QObject
from PyQt5.QtWidgets import (
QApplication,
QDialog,
QHBoxLayout,
QPushButton,
QVBoxLayout,
QTextEdit,
)
from PyQt5.QtSerialPort import QSerialPort
class Robot(QObject):
dataChanged = pyqtSignal(bytes)
def __init__(self):
super().__init__()
self.serial = QSerialPort()
self.serial.setPortName("COM2")
self.serial.setBaudRate(QSerialPort.Baud115200)
self.serial.readyRead.connect(self.handle_readData)
self.serial.open(QIODevice.ReadWrite)
self.dataChanged.connect(self.do_something)
@pyqtSlot()
def handle_readData(self):
data = self.serial.readAll()
self.dataChanged.emit(data)
@pyqtSlot(bytes)
def do_something(self, data):
pass
class State(Enum):
NoneState = auto()
VersionState = auto()
InfoState = auto()
class Demo(QDialog):
def __init__(self):
super().__init__()
layout = QHBoxLayout()
layout.setContentsMargins(0, 0, 0, 0)
self.search_bn = QPushButton("query", clicked=self.get_query_info)
layout.addStretch(1)
layout.addWidget(self.search_bn)
main_layout = QVBoxLayout(self)
main_layout.addLayout(layout)
main_layout.addWidget(QTextEdit("msg"))
self.current_state = State.NoneState
self.robot = Robot()
self.robot.dataChanged.connect(self.process_data)
@pyqtSlot()
def get_query_info(self):
self.robot.serial.write(b"show version")
self.current_state = State.VersionState
@pyqtSlot(bytes)
def process_data(self, data):
if self.current_state == State.VersionState:
do_someting(data)
self.robot.serial.write(b"show system info")
self.current_state = State.InfoState
elif self.current_state == State.InfoState:
do_someting1(data)
self.current_state = State.NoneState
if __name__ == "__main__":
import sys
app = QApplication(sys.argv)
demo = Demo()
demo.show()
sys.exit(app.exec_())