Pass binary data from QML to C++

2019-06-13 03:41发布

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?

2条回答
聊天终结者
2楼-- · 2019-06-13 04:17

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.

查看更多
\"骚年 ilove
3楼-- · 2019-06-13 04:29
// 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 :)

查看更多
登录 后发表回答