PyQt5数据在信号发出期间以字节类型

时间:2017-02-23 13:44:13

标签: python-3.x pyqt pyqt5

我正在使用PyQt5和Python 3来显示通过串口从嵌入式设备接收的一些数据。库PySerial用于处理串行通信。由于PySerial的read函数的返回类型是bytes,我使用一个线程以bytes类型发出接收的数据。有趣的是,字节b'\x00'和之后的所有字节在发送 - 接收周期中都会丢失。但是,如果发射信号的类型设置为QByteArray,则会正确发送和接收数据。

以下是重现问题的MWE:

#!/usr/bin/env python3
# -*- coding: utf-8 -*-

import sys

from PyQt5 import QtCore, QtWidgets


class Example(QtWidgets.QWidget):
    new_bytes = QtCore.pyqtSignal(bytes)
    new_qba = QtCore.pyqtSignal('QByteArray')
    bytes_to_emit = b'\x01\x00\x02'

    def __init__(self, parent=None):
        super(Example, self).__init__()
        self.init_ui()
        self.setWindowTitle('Emit Bytes Bug')

    def init_ui(self):
        emit_label = QtWidgets.QLabel('Data to emit')
        data_label = QtWidgets.QLabel(self.bytes_to_emit.hex())

        emit_bytes_button = QtWidgets.QPushButton('Emit bytes')
        emit_qba_button = QtWidgets.QPushButton('Emit QByteArray')
        self.rev_bytes_edit = QtWidgets.QLineEdit()
        self.rev_qba_edit = QtWidgets.QLineEdit()
        clear_button = QtWidgets.QPushButton('Clear receive')

        grid_layout = QtWidgets.QGridLayout()
        grid_layout.addWidget(emit_label, 0, 0)
        grid_layout.addWidget(data_label, 0, 1)
        grid_layout.addWidget(emit_bytes_button, 1, 0)
        grid_layout.addWidget(self.rev_bytes_edit, 1, 1)
        grid_layout.addWidget(emit_qba_button, 2, 0)
        grid_layout.addWidget(self.rev_qba_edit, 2, 1)
        grid_layout.addWidget(clear_button, 3, 0)

        self.setLayout(grid_layout)

        emit_bytes_button.clicked.connect(self.on_bytes_button)
        emit_qba_button.clicked.connect(self.on_qba_button)
        self.new_bytes.connect(self.update_byte_receive)
        self.new_qba.connect(self.update_qba_receive)
        clear_button.clicked.connect(self.on_clear_button)

    def update_byte_receive(self, data):
        data_str = data.hex()
        self.rev_bytes_edit.insert(data_str)

    def update_qba_receive(self, data):
        tmp_bytes = bytes(data)
        data_str = tmp_bytes.hex()
        self.rev_qba_edit.insert(data_str)

    def on_bytes_button(self):
        self.new_bytes.emit(self.bytes_to_emit)

    def on_qba_button(self):
        self.new_qba.emit(self.bytes_to_emit)

    def on_clear_button(self):
        self.rev_bytes_edit.clear()
        self.rev_qba_edit.clear()

def main():
    app = QtWidgets.QApplication(sys.argv)
    form = Example()
    form.show()
    app.exec_()

if __name__ == '__main__':
    main()

要发出的数据是b'\x01\x00\x02',点击“发送字节”即可。按钮将发出' bytes'中的数据。在按钮右侧的lineedit中键入并显示接收的数据。同样,点击发送QByteArray'按钮将以QByteArray类型发出数据,并在按钮的相应lineedit上显示接收的数据。 '清除接收'按钮只是清除lineedits。

虽然我已经知道了替代工作解决方案,即使用QByteArray类型发出字节信号,我想知道当发出信号时哪种信号类型是首选的。如果需要发出的数据已经在bytes类型,那么使用Python 3的本机bytes类型会更快吗?或者PyQt5的QByteArray更接近底层的C ++代码?任何建议都将不胜感激。

Python3版本:3.5

PyQt5版本:5.7

提前致谢

1 个答案:

答案 0 :(得分:0)

您可能需要查看Signals and Slots

的PyQt文档
  

当发出信号时,如果可能,任何参数都将转换为C ++类型。

Python Strings, Qt Strings and Unicode

  

对于Python v3,默认情况下会进行以下转换。

     
      
  • 如果Qt需要char *(或const版本),那么PyQt5将接受仅包含ASCII字符的strbytesQByteArray,   或者实现buffer协议的Python对象。

  •   
  • 如果Qt需要char(或const版本),那么PyQt5将接受与char *相同的类型,并且还需要那一个   提供了角色。

  •   
  • 如果Qt需要signed char *unsigned char *(或const版本),那么PyQt5将接受bytes

  •   
  • 如果Qt需要signed charunsigned char(或const版本),那么PyQt5将接受bytes长度为1。

  •   
  • 如果Qt期望QString,那么PyQt5将接受strbytes只包含ASCII个字符, QByteArrayNone

  •   
  • 如果Qt期望QByteArray,那么PyQt5也会接受bytes

  •   
  • 如果Qt期望QByteArray,则PyQt5也会接受仅包含str个字符的Latin-1

  •   

正如您所看到的,有C++/QtPyQt种类型bytes将愉快地转换为QByteArray个对象。它如何知道您想要new_bytes?它没有。

如果您在调试器中停止代码并查看QString信号,您将看到信号已被赋予C类型(至少这是在python2下发生的情况)。 7在我的系统上)。如果您熟悉x/00字符串的工作方式,则无论缓冲区大小如何,您都会知道字节C++表示字符串的结尾。这就是你的输出在`x / 00。

之后终止的原因

无论哪种方式,python对象都需要转换为QtCore.pyqtSignal('QByteArray')类型。使用PyQt声明信号会明确告诉class Question extends Model { public function answers() { return $this->hasMany('App\Answer'); } } 您想要哪种类型。