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

Custom QQuickItem: Updating Geometry



  • Hi,

    I have a custom QQuickItem which I use to display a x,y graph coming from a measurement device. If the measurement device delivers new data, I need to reset the QSGGeometry. I wonder whether it is possible to only append points to the end of the geometry instead of resetting it completely.



  • Isn't QSGGeometry::allocate is what you need?



  • Maybe :-). I tried it, but sometimes I receive a segfault. I should note that I guess I did not follow this rule:
    "The rule of thumb is to only use classes with the "QSG" prefix inside the QQuickItem::updatePaintNode() function." from https://doc.qt.io/qt-5.9/qtquick-visualcanvas-scenegraph.html
    So I guess the problem is that I might not call it in the right place
    My approach:

    The geometry is a member of the class.

    class PlotCurve : public QQuickItem {
    public:
      void updateGeometry(const std::vector<double>* xdata, const std::vector<double>* ydata);
    private:
      QSGGeometry * _geometry;
      QSGGeometryNode * _curve;
    

    When I had static x and y data, I set it in the constructor like this:

     _geometry = new QSGGeometry(QSGGeometry::defaultAttributes_Point2D(),xdata->size());
      QSGGeometry::Point2D *points = _geometry->vertexDataAsPoint2D();
      for(int i=0;i<xdata->size();i++) {
        points[i].x = xdata->at(i);
        points[i].y = view_y_range-ydata->at(i)+_view_y_min;
      }
    

    Here is my updateGeoemtry function

    _geometry->allocate(xdata->size());
    QSGGeometry::Point2D *points = _geometry->vertexDataAsPoint2D();
    for(int i=0;i<xdata->size();i++) {
      points[i].x = xdata->at(i);
      points[i].y = (_view_y_max-_view_y_min)-ydata->at(i)+_view_y_min;
    }
    _curve->markDirty(QSGNode::DirtyGeometry);
    

    and here my updatePaintNode

    QSGNode *PlotCurve::updatePaintNode(QSGNode *oldNode, UpdatePaintNodeData *) {
    
      QSGNode * mainNode = oldNode;
      if(!mainNode) {
        mainNode = new QSGNode;
      }
      if(!_transformNode) {
        _transformNode = new QSGTransformNode;
        mainNode->appendChildNode(_transformNode);
      }
    
      if(!_curve) {
        _geometry->setLineWidth(_curve_width);
        _geometry->setDrawingMode(GL_LINE_STRIP);
        _curve = new QSGGeometryNode;
        _curve->setFlag(QSGNode::OwnsMaterial,true);
        _curve->setFlag(QSGNode::OwnsGeometry,true);
        _curve->setGeometry(_geometry);
        QSGFlatColorMaterial* material = new QSGFlatColorMaterial;
        material->setColor(_curve_color);
        _curve->setMaterial(material);
        _transformNode->appendChildNode(_curve);
      }
    
      double transX = -_view_x_min;
      double transY = -(_view_y_max_init-_view_y_max);
    
      QMatrix4x4 m;
      m.scale(_scaleFactorX,_scaleFactorY);
      m.translate(transX, transY);
      _transformNode->setMatrix(m);
    
      return mainNode;
    
    }
    


  • So what is the correct way to update the geometry of a QQuickItem? In my case, the xdata and ydata vectors would simply grow with time and the data before would remain the same



  • No one is creating his own QQuickItems with changing geometry?


Log in to reply