不使用按钮单击更新串行数据
doesn't update serial data using button click
我的 gui 数据有问题,当我点击按钮时,我的 gui 没有更新实时值。我第一次点击我的连接按钮时它显示正确的值,但是当我改变传感器位置时,它不会更新值。在我错过代码的地方,我尝试从另一个与这个问题类似的问题中解决问题,但仍然没有解决我的问题
这是我的代码
class SerialReadThread(QThread):
received_data = pyqtSignal(QByteArray, name="receivedData")
def __init__(self, serial):
QThread.__init__(self)
self.cond = QWaitCondition()
self._status = False
self.mutex = QMutex()
self.serial = serial
def __del__(self):
self.wait()
def run(self):
while True:
self.mutex.lock()
if not self._status:
self.cond.wait(self.mutex)
buf = self.serial.read(14)
if buf:
self.received_data.emit(buf)
self.sleep(1)
self.mutex.unlock()
def toggle_status(self):
self._status = not self._status
if self._status:
self.cond.wakeAll()
@pyqtSlot(bool, name='setStatus')
def set_status(self, status):
self._status = status
if self._status:
self.cond.wakeAll()
class Form(QDialog):
received_data = pyqtSignal(QByteArray, name="receivedData")
def __init__(self):
super().__init__()
self.ui = Ui_Dialog()
self.ui.setupUi(self)
self.show()
self.serial = QSerialPort()
self.serial_info = QSerialPortInfo()
self._fill_serial_info()
self.ui.btnConnect.clicked.connect(self.slot_clicked_connect_button)
self.serial_read_thread = SerialReadThread(self.serial)
self.serial_read_thread.received_data.connect(lambda v: self.received_data.emit(v))
@staticmethod
def get_port_path():
return {"linux": '/dev/ttyS', "win32": 'COM'}[__platform__]
def _get_available_port(self):
available_port = list()
port_path = self.get_port_path()
for number in range(255):
port_name = port_path + str(number)
if not self._open(port_name):
continue
available_port.append(port_name)
self.serial.close()
return available_port
def _fill_serial_info(self):
self.ui.cmbPort.insertItems(0, self._get_available_port())
def _open(self, port_name, baudrate=QSerialPort.Baud9600):
info = QSerialPortInfo(port_name)
self.serial.setPort(info)
self.serial.setBaudRate(baudrate)
return self.serial.open(QIODevice.ReadWrite)
def connect_serial(self):
serial_info = {"port_name": self.ui.cmbPort.currentText()}
status = self._open(**serial_info)
self.received_data.connect(self.read_data)
self.serial_read_thread.start()
self.serial_read_thread.setStatus(status)
return status
def disconnect_serial(self):
return self.serial.close()
@pyqtSlot(QByteArray, name="readData")
def read_data(self, rd):
rd = str(binascii.hexlify(rd), 'ascii', 'replace')
if rd.startswith("68"):
val = rd[10:14]
self.ui.txtRaw.insertPlainText(val)
self.ui.txtRaw.insertPlainText("\n")
@pyqtSlot(name="clickedConnectButton")
def slot_clicked_connect_button(self):
if self.serial.isOpen():
self.disconnect_serial()
else:
self.connect_serial()
self.ui.btnConnect.setText({False: 'Connect', True: 'Stop'} [self.serial.isOpen()])
这是我的图形用户界面
除了你的实现至少有一个问题之外,没有必要在这种情况下使用线程:QSerialPort 是一个 QObject,应该只在单个线程中使用,因为它不是 thread-safe,这个属于 GUI 线程,因为它是在那里创建的,但您在另一个线程中使用它。
在这种情况下,您必须使用来自 QSerialPort 的 readyRead 信号:
import binascii
from PyQt5 import QtCore, QtGui, QtWidgets, QtSerialPort
from dialog_ui import Ui_Dialog
class Dialog(QtWidgets.QDialog):
def __init__(self, parent=None):
super(Dialog, self).__init__(parent)
self.ui = Ui_Dialog()
self.ui.setupUi(self)
self.ui.btnConnect.clicked.connect(self.slot_clicked_connect_button)
self.serial = QtSerialPort.QSerialPort(self)
self.serial.readyRead.connect(self.onReadyRead)
self._fill_serial_info()
def onReadyRead(self):
while self.serial.bytesAvailable() >= 14:
buff = self.serial.read(14)
rd = str(binascii.hexlify(buff), "ascii", "replace")
if rd.startswith("68"):
val = rd[10:14]
self.ui.txtRaw.insertPlainText(val)
self.ui.txtRaw.insertPlainText("\n")
def _fill_serial_info(self):
self.ui.cmbPort.clear()
for info in QtSerialPort.QSerialPortInfo.availablePorts():
self.ui.cmbPort.addItem(info.portName())
def _open(self, port_name, baudrate=QtSerialPort.QSerialPort.Baud9600):
info = QtSerialPort.QSerialPortInfo(port_name)
self.serial.setPort(info)
self.serial.setBaudRate(baudrate)
return self.serial.open(QtCore.QIODevice.ReadWrite)
def connect_serial(self):
serial_info = {"port_name": self.ui.cmbPort.currentText()}
status = self._open(**serial_info)
return status
def disconnect_serial(self):
return self.serial.close()
@QtCore.pyqtSlot(name="clickedConnectButton")
def slot_clicked_connect_button(self):
if self.serial.isOpen():
self.disconnect_serial()
else:
self.connect_serial()
self.ui.btnConnect.setText(
"Stop" if self.serial.isOpen() else "Connect"
)
if __name__ == "__main__":
import sys
app = QtWidgets.QApplication(sys.argv)
w = Dialog()
w.resize(640, 480)
w.show()
sys.exit(app.exec_())
我的 gui 数据有问题,当我点击按钮时,我的 gui 没有更新实时值。我第一次点击我的连接按钮时它显示正确的值,但是当我改变传感器位置时,它不会更新值。在我错过代码的地方,我尝试从另一个与这个问题类似的问题中解决问题,但仍然没有解决我的问题
这是我的代码
class SerialReadThread(QThread):
received_data = pyqtSignal(QByteArray, name="receivedData")
def __init__(self, serial):
QThread.__init__(self)
self.cond = QWaitCondition()
self._status = False
self.mutex = QMutex()
self.serial = serial
def __del__(self):
self.wait()
def run(self):
while True:
self.mutex.lock()
if not self._status:
self.cond.wait(self.mutex)
buf = self.serial.read(14)
if buf:
self.received_data.emit(buf)
self.sleep(1)
self.mutex.unlock()
def toggle_status(self):
self._status = not self._status
if self._status:
self.cond.wakeAll()
@pyqtSlot(bool, name='setStatus')
def set_status(self, status):
self._status = status
if self._status:
self.cond.wakeAll()
class Form(QDialog):
received_data = pyqtSignal(QByteArray, name="receivedData")
def __init__(self):
super().__init__()
self.ui = Ui_Dialog()
self.ui.setupUi(self)
self.show()
self.serial = QSerialPort()
self.serial_info = QSerialPortInfo()
self._fill_serial_info()
self.ui.btnConnect.clicked.connect(self.slot_clicked_connect_button)
self.serial_read_thread = SerialReadThread(self.serial)
self.serial_read_thread.received_data.connect(lambda v: self.received_data.emit(v))
@staticmethod
def get_port_path():
return {"linux": '/dev/ttyS', "win32": 'COM'}[__platform__]
def _get_available_port(self):
available_port = list()
port_path = self.get_port_path()
for number in range(255):
port_name = port_path + str(number)
if not self._open(port_name):
continue
available_port.append(port_name)
self.serial.close()
return available_port
def _fill_serial_info(self):
self.ui.cmbPort.insertItems(0, self._get_available_port())
def _open(self, port_name, baudrate=QSerialPort.Baud9600):
info = QSerialPortInfo(port_name)
self.serial.setPort(info)
self.serial.setBaudRate(baudrate)
return self.serial.open(QIODevice.ReadWrite)
def connect_serial(self):
serial_info = {"port_name": self.ui.cmbPort.currentText()}
status = self._open(**serial_info)
self.received_data.connect(self.read_data)
self.serial_read_thread.start()
self.serial_read_thread.setStatus(status)
return status
def disconnect_serial(self):
return self.serial.close()
@pyqtSlot(QByteArray, name="readData")
def read_data(self, rd):
rd = str(binascii.hexlify(rd), 'ascii', 'replace')
if rd.startswith("68"):
val = rd[10:14]
self.ui.txtRaw.insertPlainText(val)
self.ui.txtRaw.insertPlainText("\n")
@pyqtSlot(name="clickedConnectButton")
def slot_clicked_connect_button(self):
if self.serial.isOpen():
self.disconnect_serial()
else:
self.connect_serial()
self.ui.btnConnect.setText({False: 'Connect', True: 'Stop'} [self.serial.isOpen()])
这是我的图形用户界面
除了你的实现至少有一个问题之外,没有必要在这种情况下使用线程:QSerialPort 是一个 QObject,应该只在单个线程中使用,因为它不是 thread-safe,这个属于 GUI 线程,因为它是在那里创建的,但您在另一个线程中使用它。
在这种情况下,您必须使用来自 QSerialPort 的 readyRead 信号:
import binascii
from PyQt5 import QtCore, QtGui, QtWidgets, QtSerialPort
from dialog_ui import Ui_Dialog
class Dialog(QtWidgets.QDialog):
def __init__(self, parent=None):
super(Dialog, self).__init__(parent)
self.ui = Ui_Dialog()
self.ui.setupUi(self)
self.ui.btnConnect.clicked.connect(self.slot_clicked_connect_button)
self.serial = QtSerialPort.QSerialPort(self)
self.serial.readyRead.connect(self.onReadyRead)
self._fill_serial_info()
def onReadyRead(self):
while self.serial.bytesAvailable() >= 14:
buff = self.serial.read(14)
rd = str(binascii.hexlify(buff), "ascii", "replace")
if rd.startswith("68"):
val = rd[10:14]
self.ui.txtRaw.insertPlainText(val)
self.ui.txtRaw.insertPlainText("\n")
def _fill_serial_info(self):
self.ui.cmbPort.clear()
for info in QtSerialPort.QSerialPortInfo.availablePorts():
self.ui.cmbPort.addItem(info.portName())
def _open(self, port_name, baudrate=QtSerialPort.QSerialPort.Baud9600):
info = QtSerialPort.QSerialPortInfo(port_name)
self.serial.setPort(info)
self.serial.setBaudRate(baudrate)
return self.serial.open(QtCore.QIODevice.ReadWrite)
def connect_serial(self):
serial_info = {"port_name": self.ui.cmbPort.currentText()}
status = self._open(**serial_info)
return status
def disconnect_serial(self):
return self.serial.close()
@QtCore.pyqtSlot(name="clickedConnectButton")
def slot_clicked_connect_button(self):
if self.serial.isOpen():
self.disconnect_serial()
else:
self.connect_serial()
self.ui.btnConnect.setText(
"Stop" if self.serial.isOpen() else "Connect"
)
if __name__ == "__main__":
import sys
app = QtWidgets.QApplication(sys.argv)
w = Dialog()
w.resize(640, 480)
w.show()
sys.exit(app.exec_())