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.
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.
-
@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. -
@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.