将二进制数据从 QML 传递到 C++

Posted

技术标签:

【中文标题】将二进制数据从 QML 传递到 C++【英文标题】:Pass binary data from QML to C++ 【发布时间】:2016-12-02 20:16:47 【问题描述】:

我在 QML 内部的 javascript 中有一个“二进制字符串”,表示我想传递给 C++(通过已建立的套接字发送)的原始字节。

我使用的是这样的代码:

// QML
onSomeSignal: 
  var proto = new MyMessage();  // https://github.com/dcodeIO/protobuf.js
  var bbuf  = proto.encode();   // https://github.com/dcodeIO/bytebuffer.js
  var bytes = bbuf.toBinary();
  messageBridge.send(bytes);

// C++
void MessageBridge::send(const QString& data) 
    if(m_tcpSocket->state() == QAbstractSocket::ConnectedState) 
        m_tcpSocket->write(encodeVarint32(data.length()).toLocal8Bit());
        m_tcpSocket->write(data.toLocal8Bit());
    

但是,我发现将 JavaScript 字符串转换为 QString 有时会更改字节(可能是因为编码)。

下面的代码可以工作,但效率低下,先将字节缓冲区转换为二进制字符串,然后是 JS 数组,再转换为 QVariantList,然后逐步填充 QByteArray。

// QML
onSomeSignal: 
  var bytes = (new MyMessage()).encode().toBinary();
  var bytea = [];
  for (var i=bytes.length;i--;) bytea[i] = bytes.charCodeAt(i);
  messageBridge.send(bytes);

// C++
void MessageBridge::send(const QVariantList& data) 
    if(m_tcpSocket->state() == QAbstractSocket::ConnectedState) 
        m_tcpSocket->write(encodeVarint32(data.length()).toLocal8Bit());
        m_tcpSocket->write(data.toLocal8Bit());
        QByteArray bytes(data.length(),'\0');
        for (int i=0; i<data.length(); i++) bytes[i] = data[i].toInt();
        m_tcpSocket->write(bytes);
    

ByteBuffer 或二进制字符串从 QML/JavaScript 传递到 Qt/C++ 的有效方法是什么?

【问题讨论】:

对于我的项目使用,我最终使用QBuffer 作为设备,在QDataStream 周围实现了Data qml 包装器,并由QByteArray, implemented read and write for the basic types - bool, int, real, string, other Data` 支持。因此,如果 protobuf 不是必需品,您可以这样做并使用它,它非常简单,并且可以使用 Qt api 开箱即用。 @ddriver 感谢分享。在我的情况下,我从 QML 发送由 protobufjs 生成和编码的 protobuf,因此(自定义)ByteArray 类必须是我的数据的起点。 你可以尝试使用 base 64 编码字符串。 您是否尝试过使用 QByteArray 作为函数参数?这不应该产生任何编码。但我想主要问题是消息准备和编码是否真的需要在 GUI 中而不是在应用程序核心中完成 嗯,js 库在技术上不是 gui。 qml 也是如此——它只是标记,你可以将它用于比 gui 更多的用途。关于这个话题 - 现在是 Qt 为 JS uint8array QByteArray 实现默认转换的时候了,就像它对大多数其他重要类型一样。 【参考方案1】:
// QML
onSomeSignal: 
    var bytes = new MyMessage();
    messageBridge.send(bytes.toArrayBuffer());

并且数组缓冲区将很好地适合 QByteArray:

// C++
void MessageBridge::send(const QByteBuffer& data) 
    if (m_tcpSocket->state() == QAbstractSocket::ConnectedState) 
        m_tcpSocket->write(encodeVarint32(data.size()).toLocal8Bit());
        m_tcpSocket->write(data);

现在请告诉我如何从 C++ 中的 QByteBuffer 转到 QML 信号中有用的 protobuf.js 对象:)

【讨论】:

现在@dirtyfreebooter 只需向我们展示如何在 Qt5.8 中以另一种方式做到这一点。【参考方案2】:

Qt 5.7 不理解从 C++ 到 QML 的 QByteArray,因此它只是将其包装成一个不透明的 QVariant,使其在 QML 中无用,除非稍后将其传递回 C++。

Qt 5.8+ 增加了对 QByteArray 类型的支持。当从 C++ 传递到 QML 时,无论是作为返回变量还是信号参数,QByteArray 都会转换为 ArrayBuffer。这对 protobuf 很有用,因为 protobuf 的 javascript API 可以直接解码 ArrayBuffer 类型。

【讨论】:

在这里使用 5.9.2,将字节数组从 C++ 返回到 QML 会导致一个空的不透明对象,它没有任何属性,在 JS 中没有任何可见或可用的对象。

以上是关于将二进制数据从 QML 传递到 C++的主要内容,如果未能解决你的问题,请参考以下文章

如何将组件指针从 QML 传递到 C++?

QT怎样将一个结构体作为函数参数从C++传递到QML

将 TextStyle 从 c++ 传递到 QML

如何将 QPixmap 从 C++ 模型传递到 QML?

将 QStandardItemModel 从 C++ 传递到 QtQuick / QML TableView 并显示它

将 QObject 指针从 QML 对象传递给 C++