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. Changing the content of a QVector in a C++ model doesn’t trigger the QML bindings between the model and the custom C++ component used as a delegate

Changing the content of a QVector in a C++ model doesn’t trigger the QML bindings between the model and the custom C++ component used as a delegate

Scheduled Pinned Locked Moved Solved QML and Qt Quick
4 Posts 2 Posters 297 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.
  • J Offline
    J Offline
    JL SABATIER
    wrote on last edited by
    #1

    Good Morning,

    Here is my problem: Changing the content of a QVector in a C++ model doesn’t trigger the QML bindings between the model and the custom C++ component used as a delegate

    I’ve got a QVector in my C++ model. I’ve got a C++ custom component based on a QQuickPaintedItem.
    Adding a value in the vector of the model doesn’t trigger the bindings between the model and the component.

    Context :

    I’m trying to draw the successive results from a measurement instrument.
    This makes a curve displayed with a QQuickPaintedItem.

    I’ve got a « VolmeterChannel » class, in which I’m defining a « results » property that is accessible to the QML.
    (NB : my Voltmeter class has two channels, managed by two member classes VoltmeterChannel).

    Class VoltmeterChannel : public QObject {
        Q_OBJECT
        …
        Q_PROPERTY (QVector<QPointF> results READ get_results WRITE set_results NOTIFY resultsChanged)
        …
        QVector<QPoint> m_results ;
        …
    }
    

    Every time I get a result from the Voltmeter, I’m adding the last measurement to my result vector :

    void VoltmeterChannel::setResult(int channel, qreal result) {
        static int x=0;        
        if (m_results.count() >= NB_SAMPLES)
            m_results.removeLast();
        m_results(QPointF(x, result));
        set_results(m_results);
        ++x;
        emit resultsChanged(m_results);
    }
    

    The QML bindings are as follow :

                        Repeater {
                            model: [
                                Global.voltmeter.channel1,
                                Global.voltmeter.channel2,
                            ];
                            delegate: PaintedGraph {
                                id: _graph;
                                xMin: _graph.object.xMin;
                                xMax: _graph.object.xMax;
                                yMin: _graph.object.yMin;
                                yMax: _graph.object.yMax;
                                points: _graph.object.results;
                                visible: _graph.object.selected;
                                color: {
                                    switch (_graph.object.number) {
                                    case VoltmeterSelection.CHANNEL_1: return "#FEDB00";
                                    case VoltmeterSelection.CHANNEL_2: return "#001489";
                                    }
                                    return "gray";
                                }
                                anchors {
                                    fill: parent;
                                    topMargin: Global.theme.spaceM;
                                    leftMargin: 2;
                                    rightMargin: 2;
                                    bottomMargin: Global.theme.spaceM;
                                }
    
                                readonly property VoltmeterChannel object: modelData;
                            }
                        }
    

    I found a « quick and dirty » fix to that problem, by reconstructing a whole QVector every time and using setResults(results).

    Then, the QML bindings are triggered and the curve is drawn.
    This is working but I don’t want to copy twice every value from the QVector every time I get a new result, as this is very bad coding…

    So, how could I program this so that adding a new value in the QVector will be signaled to the QQuickPaintedItem so it will continue drawing the curve?

    JKSHJ 1 Reply Last reply
    0
    • J JL SABATIER

      Good Morning,

      Here is my problem: Changing the content of a QVector in a C++ model doesn’t trigger the QML bindings between the model and the custom C++ component used as a delegate

      I’ve got a QVector in my C++ model. I’ve got a C++ custom component based on a QQuickPaintedItem.
      Adding a value in the vector of the model doesn’t trigger the bindings between the model and the component.

      Context :

      I’m trying to draw the successive results from a measurement instrument.
      This makes a curve displayed with a QQuickPaintedItem.

      I’ve got a « VolmeterChannel » class, in which I’m defining a « results » property that is accessible to the QML.
      (NB : my Voltmeter class has two channels, managed by two member classes VoltmeterChannel).

      Class VoltmeterChannel : public QObject {
          Q_OBJECT
          …
          Q_PROPERTY (QVector<QPointF> results READ get_results WRITE set_results NOTIFY resultsChanged)
          …
          QVector<QPoint> m_results ;
          …
      }
      

      Every time I get a result from the Voltmeter, I’m adding the last measurement to my result vector :

      void VoltmeterChannel::setResult(int channel, qreal result) {
          static int x=0;        
          if (m_results.count() >= NB_SAMPLES)
              m_results.removeLast();
          m_results(QPointF(x, result));
          set_results(m_results);
          ++x;
          emit resultsChanged(m_results);
      }
      

      The QML bindings are as follow :

                          Repeater {
                              model: [
                                  Global.voltmeter.channel1,
                                  Global.voltmeter.channel2,
                              ];
                              delegate: PaintedGraph {
                                  id: _graph;
                                  xMin: _graph.object.xMin;
                                  xMax: _graph.object.xMax;
                                  yMin: _graph.object.yMin;
                                  yMax: _graph.object.yMax;
                                  points: _graph.object.results;
                                  visible: _graph.object.selected;
                                  color: {
                                      switch (_graph.object.number) {
                                      case VoltmeterSelection.CHANNEL_1: return "#FEDB00";
                                      case VoltmeterSelection.CHANNEL_2: return "#001489";
                                      }
                                      return "gray";
                                  }
                                  anchors {
                                      fill: parent;
                                      topMargin: Global.theme.spaceM;
                                      leftMargin: 2;
                                      rightMargin: 2;
                                      bottomMargin: Global.theme.spaceM;
                                  }
      
                                  readonly property VoltmeterChannel object: modelData;
                              }
                          }
      

      I found a « quick and dirty » fix to that problem, by reconstructing a whole QVector every time and using setResults(results).

      Then, the QML bindings are triggered and the curve is drawn.
      This is working but I don’t want to copy twice every value from the QVector every time I get a new result, as this is very bad coding…

      So, how could I program this so that adding a new value in the QVector will be signaled to the QQuickPaintedItem so it will continue drawing the curve?

      JKSHJ Offline
      JKSHJ Offline
      JKSH
      Moderators
      wrote on last edited by
      #2

      @JL-SABATIER said in Changing the content of a QVector in a C++ model doesn’t trigger the QML bindings between the model and the custom C++ component used as a delegate:

      Adding a value in the vector of the model doesn’t trigger the bindings between the model and the component.

      That is expected.

      The QML bindings are not triggered by modifying a variable. The QML bindings are triggered by the NOTIFY signal.

      how could I program this so that adding a new value in the QVector will be signaled to the QQuickPaintedItem so it will continue drawing the curve?

      Emit your resultsChanged() signal every time a new value is added.

      Qt Doc Search for browsers: forum.qt.io/topic/35616/web-browser-extension-for-improved-doc-searches

      1 Reply Last reply
      2
      • J Offline
        J Offline
        JL SABATIER
        wrote on last edited by JL SABATIER
        #3

        Thanks for your reply and for pointing me out where to look for the bug.
        I was trying to emit the signal, but there was a bug in the code. Which is now fixed. Thanks again.

        1 Reply Last reply
        0
        • JKSHJ Offline
          JKSHJ Offline
          JKSH
          Moderators
          wrote on last edited by
          #4

          @JL-SABATIER You're most welcome. Happy coding!

          Qt Doc Search for browsers: forum.qt.io/topic/35616/web-browser-extension-for-improved-doc-searches

          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