简体   繁体   中英

Changing QML Object value from C++

I created a QML class like

import QtQuick 2.2
import QtQuick.Controls 1.4
import QtQuick.Controls.Styles 1.4
import QtQuick.Extras 1.4

Rectangle {
    width: 80
    height: 200
    property double myVal: 15

    Timer {
        running: true
        repeat: true
        interval: 1
        onTriggered: gauge.value = myVal
    }

    Gauge {
        objectName: "gauge"
        id: gauge
        anchors.fill: parent
        anchors.margins: 10

        value: myVal
        Behavior on value {
            NumberAnimation {
                duration: 1000
            }
        }

        style: GaugeStyle {
            valueBar: Rectangle {
                implicitWidth: 16
                color: Qt.rgba(gauge.value / gauge.maximumValue, 0, 1 - gauge.value / gauge.maximumValue, 1)
            }
        }
    }
}

and I want to change value from my c++ file. To do this, I created a method which is setDataToGauge() and this method is like

void MainWindow::setDataToGauge(double newVal){

    QQmlApplicationEngine engine;
    QQmlComponent component(&engine, QUrl::fromLocalFile("gauge.qml"));
    QObject object = component.create();
    QObject *myGauge = object->findChild<QObject*>("gauge");

    if(myGauge){
        myGauge->setProperty("value",newVal);
        qDebug() << myGauge->property("value");

    }

}

this. However, it doesn't change the value of gauge. I tried different methods but it couldn't find the solution. When I drop

    Behavior on value {
        NumberAnimation {
            duration: 1000
        }
    }

this part from QML file value is changing but view of gauge is not changing. Also, I am adding to full code of my c++ file

#include "mainwindow.h"
#include "ui_mainwindow.h"
#include <QDebug>
#include <QDateTime>
#include <QtQuickWidgets/QQuickWidget>
#include <QtQml>
#include <QObject>

QObject *object;

MainWindow::MainWindow(QWidget *parent) :
    QMainWindow(parent),
    ui(new Ui::MainWindow),
    m_serial(new QSerialPort(this))
{
    ui->setupUi(this);

    ui->gaugeWidget->setSource(QUrl::fromLocalFile("gauge.qml"));
    ui->gaugeWidget->setUpdatesEnabled(true);

    QQmlApplicationEngine engine;
    QQmlComponent component(&engine, QUrl::fromLocalFile("gauge.qml"));
    object = component.create();

    setDataToGauge(60.0);
}

MainWindow::~MainWindow()
{
    delete ui;
}

void MainWindow::setDataToGauge(double newVal){

    QObject *myGauge = object->findChild<QObject*>("gauge");

    if(myGauge){
        QQmlProperty::write(myGauge, "value", newVal);
        qDebug() << myGauge->property("value");
}

}

What is the problem in there?

In your attempt of solution you are creating another gauge, and that gauge is not shown because the QQmlApplicationEngine is a local variable that will be deleted when it finishes executing, in addition QQmlApplicationEngine expects a Window or ApplicationWindow , not an Item like Rectangle .

On the other hand it is advisable to use a qresource to store the .qml because otherwise you will have to copy them every time you compile the side of your executable.

It is also not recommended to access QML objects from C ++, it is better to export a C ++ object to QML using setContextProperty() .

A simple solution is to create a signal, the signal is connected through Connections ::

*.h

#ifndef MAINWINDOW_H
#define MAINWINDOW_H

#include <QMainWindow>

namespace Ui {
class MainWindow;
}

class MainWindow : public QMainWindow
{
    Q_OBJECT

public:
    explicit MainWindow(QWidget *parent = nullptr);
    ~MainWindow();
    void setDataToGauge(double newVal);
signals:
    void dataGaugeChanged(double dataToGauge); // signal
private:
    Ui::MainWindow *ui;
};

#endif // MAINWINDOW_H

*.cpp

#include "mainwindow.h"
#include "ui_mainwindow.h"

#include <QQmlEngine>
#include <QQmlContext>


MainWindow::MainWindow(QWidget *parent) :
    QMainWindow(parent),
    ui(new Ui::MainWindow)
{
    ui->setupUi(this);
    ui->gaugeWidget->engine()->rootContext()->setContextProperty("MainWindow", this);
    ui->gaugeWidget->setSource(QUrl("qrc:/gauge.qml"));
}

MainWindow::~MainWindow()
{
    delete ui;
}

void MainWindow::setDataToGauge(double newVal){
    emit dataGaugeChanged(newVal);
}

gauge.qml

import QtQuick 2.2
import QtQuick.Controls 1.4
import QtQuick.Controls.Styles 1.4
import QtQuick.Extras 1.4

Rectangle {
    width: 80
    height: 200

    Gauge {
        id: gauge
        anchors.fill: parent
        anchors.margins: 10

        Behavior on value {
            NumberAnimation {
                duration: 1000
            }
        }

        style: GaugeStyle {
            valueBar: Rectangle {
                implicitWidth: 16
                color: Qt.rgba(gauge.value / gauge.maximumValue, 0, 1 - gauge.value / gauge.maximumValue, 1)
            }
        }
    }
    Connections{
        target: MainWindow
        onDataGaugeChanged: gauge.value = dataToGauge
    }
}

Another option is to create a Q_PROPERTY and make a binding:

*.h

#ifndef MAINWINDOW_H
#define MAINWINDOW_H

#include <QMainWindow>

namespace Ui {
class MainWindow;
}

class MainWindow : public QMainWindow
{
    Q_OBJECT
    Q_PROPERTY(double dataGauge READ dataGauge WRITE setDataGauge NOTIFY dataGaugeChanged)

public:
    explicit MainWindow(QWidget *parent = nullptr);
    ~MainWindow();

    double dataGauge() const;
    void setDataGauge(double dataGauge);
signals:
    void dataGaugeChanged();
private:
    Ui::MainWindow *ui;
    double mDataGauge;
};

#endif // MAINWINDOW_H

*.cpp

#include "mainwindow.h"
#include "ui_mainwindow.h"

#include <QQmlEngine>
#include <QQmlContext>

MainWindow::MainWindow(QWidget *parent) :
    QMainWindow(parent),
    ui(new Ui::MainWindow)
{
    ui->setupUi(this);
    ui->gaugeWidget->engine()->rootContext()->setContextProperty("MainWindow", this);
    ui->gaugeWidget->setSource(QUrl("qrc:/gauge.qml"));
}

MainWindow::~MainWindow()
{
    delete ui;
}

double MainWindow::dataGauge() const
{
    return mDataGauge;
}

void MainWindow::setDataGauge(double dataGauge)
{
    if(mDataGauge == dataGauge)
        return;
    mDataGauge = dataGauge;
    emit dataGaugeChanged();
}

*.qml

import QtQuick 2.2
import QtQuick.Controls 1.4
import QtQuick.Controls.Styles 1.4
import QtQuick.Extras 1.4

Rectangle {
    width: 80
    height: 200

    Gauge {
        id: gauge
        anchors.fill: parent
        anchors.margins: 10
        value: MainWindow.dataGauge // binding

        Behavior on value {
            NumberAnimation {
                duration: 1000
            }
        }

        style: GaugeStyle {
            valueBar: Rectangle {
                implicitWidth: 16
                color: Qt.rgba(gauge.value / gauge.maximumValue, 0, 1 - gauge.value / gauge.maximumValue, 1)
            }
        }
    }
}

Both solutions can be found in the following link .

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM