Important: Please read the Qt Code of Conduct - https://forum.qt.io/topic/113070/qt-code-of-conduct

Refreshing a QML embedded within QQuickWidget in a QWidget application



  • Hey,

    I have some 'analog' gauge to create and it appears that the best way to create them is using QtQuick. However I'm working within a qWidget environment, where the gauge's value is determined and sent to the view by a counter.

    I managed to embedded my qml view in a QQuickWidget and to bind qml and qWidget, according to a connections qml object and some signals/slots. The QQuickWidget is in a layout.

    I add a c++ function which is called every 100ms for cyclic, actions like the incrementation of a counter which has to simulate the gauge evolution.

    During the runtime, all looks good (qml text refreshed by the c++ counter incrementation) but after some iterations, all is frozen in the qml. And I really don't know why. I tried to call some update() or repaint() functions or to reload the qml source, nothing happens...

    Exists it a method to force it to refresh the printed data ?
    Could you give me an hand please ?

    piece of my code below,

    Thank you

    homePage.cpp

    #include "cpagehome.h"
    #include <QGridLayout>
    #include <QtQuick>
    
    #include "pagemanager.h"
    
    CPageHome::CPageHome(PageManager * parent)
    {
        // Save address of parent
        m_parent = parent;
    
        QQuickWidget * mp_view = new QQuickWidget;
    
        mp_data = new Data();
    
        //qmlRegisterType<Data>("DATA", 1, 0, "Data");
        mp_view->rootContext()->setContextProperty("file", mp_data);
    
        mp_data->setValue(100);
        
    //    mp_data->set_i_value(10);
    //    mp_view->rootContext()->setContextProperty("mpData",mp_data);
    
        mp_view->setAttribute(Qt::WA_AlwaysStackOnTop, true);
        mp_view->setAttribute(Qt::WA_TranslucentBackground, true);
        mp_view->setClearColor(Qt::transparent);
        mp_view->setResizeMode(QQuickWidget::SizeRootObjectToView);/* Le QML fit au qwidget */
        
        mp_view->setSource(QUrl("qrc:/testQML.qml"));
    
        // Add widget to the layout
        m_layout = new QGridLayout(this);
        m_layout->addWidget(mp_view);
    
    }
    
    void CPageHome::onActive(int activePage)
    {
        /* called every 100 ms */
        static int hi_value = mp_data->getValue();
    
        mp_data->setValue(hi_value);
    
    //    mp_view->engine()->clearComponentCache();
    //    mp_view->setSource(QUrl(QStringLiteral("qrc:/testQML.qml")));
    
    
        /*
        if (hi_value % 2 == 0)
        {
            m_parent->showButtons(100);
        }
    */
    
        qDebug() << "mp_data: " << mp_data->getValue() ;
        //mp_view->rootContext()->setContextProperty("mpData",mp_data);
        //mp_view->setSource(QUrl(QStringLiteral("qrc:/testQML.qml")));
        //mp_view->repaint();
        //mp_view->update();
    
        //mp_view->resize(10*hi_value,10*hi_value);
        //m_layout->removeWidget(mp_view);
    
        //m_layout->addWidget(btn,1,2);
        //mp_view->adjustSize();
        //mp_view->updateGeometry();
    
        hi_value +=1;
    }
    
    CPageHome::~CPageHome()
    {
    
    }
    
    

    datafile.cpp, used to transfer data between qml and qWidget

    #include "data.h"
    
    Data::Data()
    {
        mi_value = 0;
    }
    
    Data::~Data()
    {
    
    }
    
    int Data::getValue(void)
    {
        return mi_value;
    }
    
    void Data::setValue(int oi_value)
    {
        mi_value = oi_value;
        emit valueChanged(mi_value);
    }
    
    

    datafile.h

    #ifndef DATA_H
    #define DATA_H
    
    #include <QObject>
    #include <QWidget>
    
    class Data : public QObject
    {
        Q_OBJECT
    
        Q_PROPERTY(int value READ getValue WRITE setValue NOTIFY valueChanged)
    public:
        Data();
        virtual ~Data();
        Q_INVOKABLE int getValue(void);
        Q_INVOKABLE void setValue(int oi_value);
    
    signals:
        void valueChanged(int oi_value);
    
    private:
        int mi_value;
    };
    
    #endif // DATA_H
    
    

    testQML.qml

    import QtQuick 2.4
    import QtQuick.Controls 1.0
    
    Item {
        width: 800
        height: 480
    
        Rectangle{
            id: rect
            anchors.horizontalCenter: parent.horizontalCenter
            anchors.verticalCenter: parent.verticalCenter
            height: parent.height/3
            width: height
            color: 'coral'
    
            Text{
                id: textBox
                text: file.getValue()
                onTextChanged: {
                    textBox.text = connection.newValue;
                }
    
                Connections{
                    id: connection
                    target: file
                    property int newValue: 1000
                    onValueChanged:
                    {
                        console.log("oi_value : " + oi_value);
                        newValue = oi_value;
                        textBox.text = oi_value + '';
                    }
                }
            }
        }
    }
    
    

    A QTimer in the pageManager is launched at the beginning, and generates signals to call onActive function.



  • Anyone has any idea ? :/ I'm really stuck


  • Moderators

    hi @Alexiss and welcome

    one thing jumps to my mind, you should actually check if the value differs - that's the standard way to do it, and you should check if the setValue function is still called and just the Ui doesn't display the change.

    void Data::setValue(int oi_value)
    {
       qDebug() << Q_FUNC_INFO << oi_value << "same value?" << (mi_value == oi_value);
        if(mi_value == oi_value)
           return;
        mi_value = oi_value;
        emit valueChanged(mi_value);
    }
    


  • @J.Hilk Thanks for your test, I checked it and the setValue function is normally called with the right value and the display still doesn't display the change.