Skip to content
  • Categories
  • Recent
  • Tags
  • Popular
  • Users
  • Groups
  • Search
  • Get Qt Extensions
  • Unsolved
Collapse
Brand Logo
  1. Home
  2. Qt Development
  3. QML and Qt Quick
  4. Pass data between qtquick controls (slider) and C++ application

Pass data between qtquick controls (slider) and C++ application

Scheduled Pinned Locked Moved QML and Qt Quick
8 Posts 2 Posters 3.8k Views
  • Oldest to Newest
  • Newest to Oldest
  • Most Votes
Reply
  • Reply as topic
Log in to reply
This topic has been deleted. Only users with topic management privileges can see it.
  • sajis997S Offline
    sajis997S Offline
    sajis997
    wrote on last edited by
    #1

    Hello ,

    I am facing some confusion regarding passing data between the qt qick slider and QQuickItem object in C++, that results in application crash. I have the following class with the defined properties:

    [code]
    class TessellationSceneItem : public QQuickItem
    {
    Q_OBJECT
    //the property defintion must be at the top of the class
    //the notify signal is needed for correct property bindings
    Q_PROPERTY(float outer READ outer WRITE setOuter NOTIFY outerChanged)
    Q_PROPERTY(float inner READ inner WRITE setInner NOTIFY innerChanged)
    Q_PROPERTY(float maxPatchVertices READ maxPatchVertices NOTIFY maxPatchVerticesChanged)

    public:
    TessellationSceneItem();
     
    void setOuter(float);
    void setInner(float);
     
    float inner();
    float outer();
     
    float maxPatchVertices() const;
     
    signals:
    void innerChanged();
    void outerChanged();
    void maxPatchVerticesChanged();
    .............
    ............
    private:
     
    TeapotTessellation* mTessScene;
     
    QTime mTIme;
     
    };
    

    [/code]

    The definition of the setter and getter methods:

    [code]
    void TessellationSceneItem::setOuter(float outerFactor)
    {
    if(outerFactor == mTessScene->outerTessellationFactor())
    return;

    mTessScene->setOuterTessellationFactor(outerFactor);
    //do not emit notifier if value does not actually change
    emit outerChanged();
    }
     
    void TessellationSceneItem::setInner(float innerFactor)
    {
    if(innerFactor == mTessScene->innerTessellationFactor())
    return;
     
    mTessScene->setInnerTessellationFactor(innerFactor);
    emit innerChanged();
    }
     
    float TessellationSceneItem::inner()
    {
    return (float)(mTessScene->innerTessellationFactor());
    }
     
    float TessellationSceneItem::outer()
    {
    return (float)(mTessScene->outerTessellationFactor());
    }
     
    float TessellationSceneItem::maxPatchVertices() const
    {
    return (float) (mTessScene->getMaxPatchVertices());
    }
    

    [/code]

    The idea is to have the slider value loaded with the value set in the underlying C++ application. Then with every slider interaction , the underlying value( outer, inner) in the C++ side will be updated. I tried the following in the .qml file , but the application crashes.

    [code]
    import QtQuick 2.0
    import QtQuick.Controls 1.1
    import QtQuick.Layouts 1.1
    import TeapotTessellation 1.0

    Item {
    id: root
    width: 512; height: 512
     
     
    TessellationSceneItem
    {
    id: tessSceneItem
    // outer: outerTessellationSlider.value
    // inner: innerTessellationSlider.value
    }
     
    GridLayout {
    id: controlLayout
    columns: 2
     
    Text {
    id: outerTessellationText
    text: qsTr("Outer Tess. Factor: ")
    color: "black"
    opacity: 1.0
    }
     
    Slider {
    id: outerTessellationSlider
    opacity: 1.0
    // value: tessSceneItem.outer
    minimumValue: 1.0
    maximumValue: 64//tessSceneItem.maxPatchVertices
    stepSize: 1.0
    Layout.fillWidth: true
    }
     
     
    Text {
    id: innerTessellationText
    text: qsTr("Inner Tess. Factor: ")
    color: "black"
    opacity: 1.0
    }
     
     
     
    Slider {
    id: innerTessellationSlider
    opacity: 1.0
    // value: tessSceneItem.inner
    minimumValue: 1.0
    maximumValue: 64.0//tessSceneItem.maxPatchVertices
    stepSize: 1.0
    Layout.fillWidth: true
    }
    }
     
     
    Rectangle {
    id: rect
    color: "red"
    radius: 10
    opacity: 0.1
    border.color: "black"
    anchors.fill: controlLayout
    }
    }
    

    [/code]

    The commented part of the .qml file are the places that cause the application crash.

    Even assigning fixed values for inner / outer inside the .qml file results in application crash. I tried as follows:

    [code]
    Q_PROPERTY(float inner READ inner WRITE setInner NOTIFY innerChanged)
    [/code]

    Then inside the .qml file I have the following snippet:

    [code]
    TessellationSceneItem
    {
    id: tessSceneItem

    inner: 10
    }
    

    [/code]

    I get the crashing point while running with debugger at the following points:

    [code]
    void TessellationSceneItem::setInner(float innerFactor)
    {
    if(innerFactor == mTessScene->innerTessellationFactor())
    return;

    mTessScene->setInnerTessellationFactor(innerFactor);
    emit innerChanged();
    }
     
    ..............................
    ..............................
     
    GLfloat TeapotTessellation::innerTessellationFactor()
    {
    return mInnerTessellationFactor;
    }
    

    [/code]

    I am clueless. Any one in the forum would like to address this issue ?

    The slider value is of qreal type , where the C++ side is of float type. Do I have to do any explicit casting ? If yes, where do I have to do it?

    Thanks

    1 Reply Last reply
    0
    • p3c0P Offline
      p3c0P Offline
      p3c0
      Moderators
      wrote on last edited by
      #2

      Hi,

      Just a silly question, have you initialized TeapotTessellation ?

      157

      1 Reply Last reply
      0
      • sajis997S Offline
        sajis997S Offline
        sajis997
        wrote on last edited by
        #3

        If the following is what you ask , then I guess , yes:

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

        /*
         * any QObject derived C++ class can be registered as the definiton of a QML object type. Once a class is registered
         * with the QML type system, the class can be declared and instantiated like any other object type
         * from QML code. Once created, a class instance can be manipulated from QML. And the properties, methods and signals
         * of any QObject-derived class are accessible from QML code.
         * */
        qmlRegisterType<TessellationSceneItem>("TeapotTessellation",1,0,"TessellationSceneItem");
        
        QQuickView view;
        //The view will automatically resize the root item to the size of the view.
        view.setResizeMode(QQuickView::SizeRootObjectToView);
        view.setSource(QUrl("qrc:///qml/main.qml"));
        view.show();
        
        return app.exec();
        

        }
        [/code]

        As you see from the last post that that slider value type is qreal in the qml whereas , on the C++ side i am dealing with float type as follows:

        [code]
        //the property defintion must be at the top of the class
        //the notify signal is needed for correct property bindings
        Q_PROPERTY(float outer READ outer WRITE setOuter NOTIFY outerChanged)
        Q_PROPERTY(float inner READ inner WRITE setInner NOTIFY innerChanged)
        Q_PROPERTY(float maxPatchVertices READ maxPatchVertices NOTIFY maxPatchVerticesChanged)
        [/code]

        Could that be the reason behind the crash. Where and when to make this casting, if it is mandatory?

        Thanks

        1 Reply Last reply
        0
        • p3c0P Offline
          p3c0P Offline
          p3c0
          Moderators
          wrote on last edited by
          #4

          That is just the registration of TessellationSceneItem so that you can use it as a Component in QML. But in TessellationSceneItem code you have used TeapotTessellation object in one of the function:
          @
          void TessellationSceneItem::setInner(float innerFactor)
          {
          if(innerFactor == mTessScene->innerTessellationFactor())
          return;
          ...
          }
          @

          where mTessScene is object of class TeapotTessellation. Have you initialized this one ?

          157

          1 Reply Last reply
          0
          • sajis997S Offline
            sajis997S Offline
            sajis997
            wrote on last edited by
            #5

            yes i have, as follows:

            [code]
            void TessellationSceneItem::sync()
            {
            if(!mTessScene)
            {
            //initialize the tessellation renderer
            mTessScene = new TeapotTessellation();

                //start tracking the time
                mTIme.start();
            
                //make the connection to render the opengl scene before the scene graph rendering
                connect(window(),SIGNAL(beforeRendering()),mTessScene,SLOT(paint()),Qt::DirectConnection);
            
                QTimer *timer = new QTimer();
                connect(timer,SIGNAL(timeout()),this,SLOT(updateTime()),Qt::DirectConnection);
                timer->start();
            }
            
            
            mTessScene->setViewportSize(window()->width() * window()->devicePixelRatio(),
                                        window()->height() * window()->devicePixelRatio());
            
            //set  the timer value from the qml to the mTessScene
            //in other words, copy the state of the item into the renderer
            

            }

            [/code]

            And the above gets called in the following manner:

            [code]
            TessellationSceneItem::TessellationSceneItem()
            :mTessScene(0)
            {
            connect(this,SIGNAL(windowChanged(QQuickWindow*)),this,SLOT(handleWindowChanged(QQuickWindow*)));
            }

            void TessellationSceneItem::handleWindowChanged(QQuickWindow *win)
            {
            if(win)
            {
            connect(win,SIGNAL(beforeSynchronizing()),this,SLOT(sync()),Qt::DirectConnection);
            connect(win,SIGNAL(sceneGraphInvalidated()),this,SLOT(cleanup()),Qt::DirectConnection);

                //define the opengl surface format
                //with the most modern profile
                //while retaining the compatibility profile
                QSurfaceFormat f = win->format();
                f.setMajorVersion(4);
                f.setMinorVersion(3);
                f.setSamples(4);
                f.setStencilBufferSize(8);
                f.setProfile&#40;QSurfaceFormat::CompatibilityProfile&#41;;
            
                win->setFormat(f);
            
                win->setClearBeforeRendering(false);
            }
            

            }

            [/code]

            1 Reply Last reply
            0
            • p3c0P Offline
              p3c0P Offline
              p3c0
              Moderators
              wrote on last edited by
              #6

              Ok.. This seems to be good. Now, from your first post
              @
              void TessellationSceneItem::setInner(float innerFactor)
              {
              if(innerFactor == mTessScene->innerTessellationFactor())
              return;

                  mTessScene->setInnerTessellationFactor(innerFactor);
                  emit innerChanged();
                  }
                   
                  ..............................
                  ..............................
                   
                  GLfloat TeapotTessellation::innerTessellationFactor()
                  {
                  return mInnerTessellationFactor;
                  }
              

              @

              Where do you exactly get the crash ? During mTessScene->setInnerTessellationFactor(innerFactor) ?
              How does setInnerTessellationFactor look like ?

              157

              1 Reply Last reply
              0
              • sajis997S Offline
                sajis997S Offline
                sajis997
                wrote on last edited by
                #7

                Hello

                The issue is resolved now. Let me explain how I solved it. I have been following the documentation "Scene Graph - OpenGL Under QML" as a standard to adapt to my own project. According to it the renderer was initialized a bit later as follows:

                [code]
                void Squircle::sync()
                {
                if (!m_renderer) {
                m_renderer = new SquircleRenderer();
                connect(window(), SIGNAL(beforeRendering()), m_renderer, SLOT(paint()), Qt::DirectConnection);
                }
                m_renderer->setViewportSize(window()->size() * window()->devicePixelRatio());
                m_renderer->setT(m_t);
                }
                [/code]

                In my project i did something similar as follows:

                [code]
                void TessellationSceneItem::sync()
                {
                if(!mTessScene)
                {
                //initialize the tessellation renderer
                mTessScene = new TeapotTessellation();

                    //start tracking the time
                    mTIme.start();
                
                    //make the connection to render the opengl scene before the scene graph rendering
                    connect(window(),SIGNAL(beforeRendering()),mTessScene,SLOT(paint()),Qt::DirectConnection);
                
                    QTimer *timer = new QTimer();
                    connect(timer,SIGNAL(timeout()),this,SLOT(updateTime()),Qt::DirectConnection);
                    timer->start();
                }
                
                    mTessScene->setViewportSize(window()->width() * window()->devicePixelRatio(),
                                            window()->height() * window()->devicePixelRatio());
                

                }
                [/code]

                But the the Qt's Property System call the property setter and getter function right after the instantiation of the TessellationSceneItem, while the TeapotTessellation* mTessScene is not initialized yet. This is why i was getting the application crash. Now i moved the renderer class object instantiation inside the constructor of TessellationSceneItem as follows:

                [code]
                TessellationSceneItem::TessellationSceneItem()
                :mTessScene(0)
                {

                //initialize the tessellation renderer
                mTessScene = new TeapotTessellation();
                
                //start tracking the time
                mTIme.start();
                
                QTimer *timer = new QTimer();
                connect(timer,SIGNAL(timeout()),this,SLOT(updateTime()),Qt::DirectConnection);
                timer->start();
                
                connect(this,SIGNAL(windowChanged(QQuickWindow*)),this,SLOT(handleWindowChanged(QQuickWindow*)));
                

                }
                [/code]

                Now I am encountering a new issue, i think it could be addressed in the same thread.

                The slider control inside the qml file has a property called "maximumValue" and it contains a value that depends on the opengl initialization of the underlying renderer class.

                [code]
                class TessellationSceneItem : public QQuickItem
                {
                Q_OBJECT
                ......................
                ......................
                Q_PROPERTY(float maxPatchVertices READ maxPatchVertices CONSTANT)

                .....................
                .....................
                };
                [/code]

                Once the TessellationSceneItem is initialized the maxPatchVertices is called and it is containing the value 0 since by then the opengl initialization has not executed yet. How to deal with this issue. This "maxPatchVertices" contains the value for the slider value for "maximumValue" and "maxPatchVertices" comes from the opengl function

                [code]
                glGetIntegerv(GL_MAX_PATCH_VERTICES,&mMaxPatchVertices);
                [/code]

                The above function should return some value greater than 0 . I am getting 0 instead. Is there any way slider get the updated value in the qml side. The value remain constant in the qml side. Thats whay i have CONSTANT defined the peoperty definition.

                In a nutshell i would like to have the maximum vertices per patch to be assingned to the property maxPatchVertices and accessible in qml. I am not getting the correct one .

                Any hint to get it done ?

                Thanks

                1 Reply Last reply
                0
                • sajis997S Offline
                  sajis997S Offline
                  sajis997
                  wrote on last edited by
                  #8

                  Hello forum,

                  I did not get much of a response from my last post. I believe that I did not explain the issue well enough. Let me try again. Consider the following class structures:

                  [code]

                  class A : public QObject
                  {
                  Q_OBJECT

                  public:

                    A();
                   ~A();
                  
                   void initialize();
                  
                   GLint method1();
                  

                  private:

                   GLint var1;
                  

                  }
                  [/code]

                  Lets describe a bit about the class A. The public method method1() returns the value for var1. The initialize() must be called prior calling method1() so that the member variale value contains the updated value.

                  Now lets look into another class as follows:

                  [code]

                  class B : public QQuickItem
                  {
                  Q_OBJECT

                  public:
                  
                     B();
                  
                     Q_INVOKABLE float method2();
                  

                  private:

                    float var2;
                  
                   A* a;
                  

                  };

                  ................
                  ................

                  B::B()
                  {
                  a = new A();
                  }

                  float B::method2()
                  {
                  return (float)(a->method1());
                  }

                  [/code]

                  While running the program I found that B::method2() is always returning ZERO, which is incorrect value. The method2 is called from the qml file as follows:

                  [code]

                  BItem
                  {
                      id: bItem
                  }
                  
                       Slider {
                           id: slider1
                           opacity: 1.0           
                           minimumValue: 1.0
                           maximumValue: bItem.maxPatchVertices()
                           stepSize: 1.0
                           Layout.fillWidth: true
                  
                           onValueChanged: bItem.outer = value
                       }
                  

                  [/code]

                  I tried the understand the program flow with the help of the debugger and found that B::method() is called and the value is not updated even after the A::initialize() changes the value. I have seen examples where C++ class member variable is updated from the qml , not vice versa. I believe I am experiencing the latter issue here. As you can see from the qml file, I trying to get the updated value from C++ class member function and set it as a property value fom the slider.

                  Any idea/refference/example to resolve this ?

                  Thanks

                  1 Reply Last reply
                  0

                  • Login

                  • Login or register to search.
                  • First post
                    Last post
                  0
                  • Categories
                  • Recent
                  • Tags
                  • Popular
                  • Users
                  • Groups
                  • Search
                  • Get Qt Extensions
                  • Unsolved