How to redraw a custom QQuickItem



  • I have created a custom QML Element by extending QQuickItem and overriding the updatePaintNode() function. I am drawing two lines on my application which will expand or shrink in size based on the block size that gets added on the left side of the application. This block can be added in small and big modes and can be removed by selecting the buttons on the top bar.

    This is my code:

    line.cpp

    #include <QSGGeometry>
    #include <QSGGeometryNode>
    #include <qsgnode.h>
    #include <qsgflatcolormaterial.h>
    #include "line.h"
    
    Lines::Lines(QQuickItem *parent) : QQuickItem(parent) {
        setFlag(QQuickItem::ItemHasContents, true);
    }
    
    Lines::~Lines() {}
    
    QSGNode *Lines::updatePaintNode(QSGNode *oldNode, UpdatePaintNodeData *) {
        QSGGeometryNode *node = NULL;
        QSGGeometry *geometry = NULL;
        QSGGeometry::Point2D *vertices;
        QSGFlatColorMaterial *material;
        int points = 0;
        int lineHeight = 0;
        int ys = 0;
        int xs;
        int xe;
    
        points = width();
    
        if (!oldNode)
        {
            node = new QSGGeometryNode;
            geometry = new QSGGeometry(QSGGeometry::defaultAttributes_Point2D(), points);
            geometry->setLineWidth(1);
            geometry->setDrawingMode(GL_LINES);
            node->setGeometry(geometry);
            node->setFlag(QSGNode::OwnsGeometry);
            material = new QSGFlatColorMaterial;
            material->setColor("white");
            node->setMaterial(material);
            node->setFlag(QSGNode::OwnsMaterial);
        }
        else
        {
            node = static_cast<QSGGeometryNode *>(oldNode);
            geometry = node->geometry();
            geometry->allocate(points);
        }
    
        vertices = geometry->vertexDataAsPoint2D();
        lineHeight = (height() / 4);
    
        xs = 0;
        xe = width() - xs;
    
        for(int i = 0; i < 2; i++)
        {
            ys = ( i * lineHeight);
            vertices[(2*i)].set(xs, ys);
            vertices[(2*i)+1].set(xs + xe, ys);
        }
    
        node->markDirty(QSGNode::DirtyForceUpdate);
        return node;
    }
    

    line.h

    #include <QQuickItem>
    class Lines : public QQuickItem
    {
        Q_OBJECT
    public:
        Lines(QQuickItem *parent = 0);
        ~Lines();
    
        QSGNode *updatePaintNode(QSGNode *, UpdatePaintNodeData *);
    };
    

    main.cpp

    #include <QGuiApplication>
    #include <QQmlApplicationEngine>
    #include "line.h"
    
    int main(int argc, char *argv[])
    {
        QGuiApplication app(argc, argv);
    
        QQmlApplicationEngine engine;
        qmlRegisterType<Lines>("lines", 1, 0, "Lines");
    
        engine.load(QUrl(QStringLiteral("qrc:/main.qml")));
    
        return app.exec();
    }
    

    main.qml

    import QtQuick 2.4
    import QtQuick.Window 2.2
    import QtQuick.Controls 1.0
    import lines 1.0
    
    Window {
        id: canvas
    
        height: 500
        width: 500
        color: "black"
        visible: true
    
        Rectangle {
            id: topBar
    
            height: 40
            Row {
                spacing: 10
                Button {
                    text: "Small"
                    onClicked: {
                        rect.visible = true
                        rect.width = 50
                    }
                }
                Button {
                    text: "Big"
                    onClicked: {
                        rect.visible = true
                        rect.width = 100
                    }
                }
                Button {
                    text: "None"
                    onClicked: {
                        rect.visible = false
                        rect.width = 0
                    }
                }
            }
        }
    
        Rectangle {
            id: rect
    
            anchors {
                left: parent.left
                top: topBar.bottom
                bottom: parent.bottom
            }
    
            color: "grey"
            visible: false
        }
    
        Rectangle {
            id: rect2
    
            anchors {
                left: rect.right
                right: parent.right
                top: topBar.bottom
                bottom: parent.bottom
            }
    
            color: "black"
    
            Lines {
                id: lines
    
                x: 0
                y: 100
    
                width: parent.width
                height: 225
            }
        }
    }
    

    I am seeing that when I select the left Grey block (using the buttons) the Lines were not redrawn properly and I see some glitches. The attached picture below shows my output with glitches.

    0_1499167266627_fS7Lo.png

    I have tried calling node->markDirty(QSGNode::DirtyForceUpdate) but it is of no use.

    How can I fix this issue. Please help. Thanks in advance.


  • Moderators

    @chaithubk
    simply call update() like you would do for a QWidget



  • @raven-worx You mean like I need to call Lines::update() in the updatePaintNode() function ? I have not worked on Qt Widgets. So am little confused with your solution.


  • Moderators

    @chaithubk
    whenever data relevant for drawing has changed call update() on the QQuickItem and a call to updatePaintNode() (-> painting) is scheduled.
    Like in is mentioned in the link to the docs i've posted.


Log in to reply
 

Looks like your connection to Qt Forum was lost, please wait while we try to reconnect.