将二进制数据从 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++的主要内容,如果未能解决你的问题,请参考以下文章