Pass binary data from QML to C++

≯℡__Kan透↙ 提交于 2019-12-12 10:24:59

问题


I have a 'binary string' in JavaScript inside of QML, representing raw bytes that I want to pass to C++ (to send over an established socket).

I was using code like this:

// 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());
    }
}

However, I discovered that translating the JavaScript string to a QString was sometimes changing the bytes (presumably because of encodings).

The following code works, but it's inefficient, converting the byte buffer to a binary string, then a JS array, converting to a QVariantList and then piecemeal populating a 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);
    }
}

What is an efficient way to pass either a ByteBuffer or binary string from QML/JavaScript to Qt/C++, in a way that gives me something I can write to a QTcpSocket?


回答1:


// QML
onSomeSignal: {
    var bytes = new MyMessage();
    messageBridge.send(bytes.toArrayBuffer());
}

and the array buffer will nicely fit into a 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);
}

Now please tell me how to go the other way from a QByteBuffer in C++ to a useful protobuf.js object in a QML signal :)




回答2:


Qt 5.7 does not understand QByteArray from C++ to QML, so it just wraps it into an opaque QVariant, making it useless in QML, except for passing it back into C++ at a later time.

Qt 5.8+ adds support for QByteArray type. When passed from C++ to QML, either as a return variable or a signal parameter, the QByteArray is converted to an ArrayBuffer. This is useful for protobufs, as the protobuf's javascript API can directly decode an ArrayBuffer type.



来源:https://stackoverflow.com/questions/40940199/pass-binary-data-from-qml-to-c

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!