Двусторонняя связь между 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();
}

myclass.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 и до сих пор не могу этого сделать:(

2 ответа

Решение

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

MyClass.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"));
};

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

Вы можете установить свойство в 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);

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

Здесь все очень хорошо объяснено

Другие вопросы по тегам