Двустороннее соединение между QML/QtQuick и QWidget

Я пытаюсь создать приложение, которое будет использовать QSerialPort и QtQuick, поэтому мне нужно каким-то образом подключить настольное приложение к QML. Мне удалось (хорошо, я скопировал и внес некоторые изменения) отправить информацию из QML в main.cpp, но я не могу отправить что-либо по-другому. Желаемый эффект состоит в том, чтобы управлять всем из .cpp, добавлять и удалять ListElements и отправлять параметры для рисования графика.

main.cpp
int main(int argc, char *argv[]) {
    QApplication app(argc, argv);
    QQuickView view(QUrl::fromLocalFile("path/main.qml"));
    QObject *item = view.rootObject();
    MyClass myClass,mySecondClass;
    QObject::connect(item, SIGNAL(qmlSignal(QVariant)),
                     &myClass, SLOT(cppSlot(QVariant)));
    QObject::connect(&myClass, SIGNAL(Nazwa(QVariant)),
                     item, SLOT(onNazwa(QVariant)));
    QVariant c=200;
    emit myClass.Nazwa(c);

    view.show();
    return app.exec();
}

мой класс.h

#ifndef MYCLASS_H
#define MYCLASS_H
#include <QObject>
#include <QDebug>
#include <QQuickItem>
class MyClass : public QObject
{
    Q_OBJECT
public:
    explicit MyClass(QObject *parent = 0);

signals:
    void Nazwa(QVariant a);

public slots:
    void cppSlot(const QVariant &v) {
       qDebug() << "QVariant :):" << v;

       QQuickItem *item =
           qobject_cast<QQuickItem*>(v.value<QObject*>());
       qDebug() << "Wymiary:" << item->width()
                << item->height();
    }

};

#endif // MYCLASS_H

main.qml

import QtQuick.Window 2.0
import QtQuick 2.0

Item {
    id: item
    width: 100; height: 100
//    Item{
//        id: item2
//        onNazwa: {    }
//    }
    signal qmlSignal(var anObject)
    MouseArea {
        anchors.fill: parent
        onClicked: {
            parent.width=200;
            item.qmlSignal(item)
        }
    }
}

Также любые изменения в main.qml разорвут первое соединение, и я даже не знаю почему. Можете ли вы дать мне совет или пример? Я потратил 2-й день на документацию Qt, и я до сих пор не могу этого сделать :(


person Marcin Plebanek    schedule 20.05.2016    source источник


Ответы (2)


ХОРОШО. Я понимаю, что вы хотите, но я рекомендую вам использовать engine. Попробуйте код ниже. Я использовал очень простой пример только для того, чтобы показать, как это сделать, не более того.

Мой класс .H:

#include <QObject>
#include <QSerialPort>

class MyClass : public QObject
{
    Q_OBJECT
    QSerialPort *_port;
public:
    explicit MyClass(QObject *parent = 0);

signals:
    void sendData(const QString &data);

public slots:
    void startCom(const QString &name, int baud);
    void read();
    void writeData(const QByteArray &data = QByteArray("data"));
};

Мой класс .CPP:

MyClass::MyClass(QObject *parent) : QObject(parent)
{
}

void MyClass::startCom(const QString &name, int baud)
{
    _port = new QSerialPort(name, this);
    _port->setBaudRate(baud);
    if(_port->open(QIODevice::ReadWrite))
        connect(_port, &QSerialPort::readyRead, this, &MyClass::read);
    else
        emit sendData(tr("Error"));
}

void MyClass::read()
{
    emit sendData(QString::fromStdString(_port->readAll().toStdString()));
}

void MyClass::writeData(const QByteArray &data)
{
    _port->write(data);
}

main.cpp:

int main(int argc, char *argv[])
{
    QGuiApplication app(argc, argv);

    qmlRegisterType<MyClass>("com.some.myclass", 1, 0, "MyClass");
    QQmlApplicationEngine engine;
    engine.load(QUrl(QStringLiteral("qrc:/main.qml")));

    return app.exec();
}

main.qml:

import QtQuick 2.6
import QtQuick.Window 2.2
import QtQuick.Layouts 1.1
import QtQuick.Controls 1.4
import com.some.myclass 1.0

Window {
    id: root
    signal startPort(string name, int baud)
    width: 640
    height: 480
    ColumnLayout {
        id: colLay
        TextField {
            id: comName
            placeholderText: qsTr("COM-port name")
        }
        ComboBox {
            id: baud
            model: [ 9600, 19200, 115200 ]
        }
        Button {
            id: portBut
            text: qsTr("Start serial")
            onClicked: root.startPort(comName.text, baud.currentText)
        }
        Button {
            id: sendBut
            text: qsTr("Write data")
            onClicked: comClass.writeData
        }
        Label {
            id: dataLbl
            text: qsTr("No data")
        }
    }
    MyClass {
        id: comClass
        onSendData: dataLbl.text = data
    }

    onStartPort: comClass.startCom(name, baud)

    Component.onCompleted: root.show();
}
person someoneinthebox    schedule 22.05.2016

Вы можете установить свойство в qml и реагировать на его изменение.

main.qml

Item {
    id: item
    property alias nazwa: item2.nazwa

    Item{
        id: item2
        property var nazwa: null
        onNazwaChanged: {} 
    }
}

и на main.cpp

QQmlProperty::write(item, "nazwa", 10);

В качестве альтернативы вы можете вызвать метод непосредственно из С++ в qml.

Все очень хорошо объяснено здесь

person perencia    schedule 21.05.2016