Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Periodically redraw QQuickItem

Tags:

c++

qt

qml

I have created a custom QML Element by extending QQuickItem and overriding the updatePaintNode() function.

Since I need to draw rectangles along a timeline which will grow in real-time I need the GUI to be redrawn for every new frame.

Is there a way to have the updatePaintNode() function be executed periodically for every new frame?

I have tried calling node->markDirty(QSGNode::DirtyForceUpdate) which did not cause the updatePaintNode() function to be called periodically.

Edit: this is what my code looks like:

QSGNode *PianoRoll::updatePaintNode(QSGNode *n, QQuickItem::UpdatePaintNodeData *data)
{
    QSGGeometryNode *node = static_cast<QSGGeometryNode *>(n);
    if (!node)
    {
        node = new QSGSimpleRectNode(boundingRect(), Qt::white);
    }

    node->removeAllChildNodes();

    qreal msPerScreen = 10000;
    qreal pitchesPerScreen = 128;
    qreal x_factor = (qreal) boundingRect().width() / msPerScreen;
    qreal y_factor = (qreal) boundingRect().height() / pitchesPerScreen;

    for (unsigned int i = 0; i < m_stream->notes.size(); i++)
    {
        shared_ptr<Note> note = m_stream->notes.at(i);
        qreal left = boundingRect().left() + note->getTime() * x_factor;
        qreal top = boundingRect().top() + note->getPitch() * y_factor;
        qreal width;
        qreal height = y_factor;

        if (note->getDuration() != 0)
        {
            width = note->getDuration() * x_factor;
        }
        else
        {
            // TODO
            width = 500 * x_factor;

        }

        QRectF noteRectangle = QRectF(left, top, width, height);
        node->appendChildNode(new QSGSimpleRectNode(noteRectangle, Qt::black));
    }
    node->markDirty(QSGNode::DirtyForceUpdate);
    return node;
}
like image 622
user2052244 Avatar asked Oct 18 '13 17:10

user2052244


1 Answers

From the documentation of updatePaintNode:

The function is called as a result of QQuickItem::update(), if the user has set the QQuickItem::ItemHasContents flag on the item.

You need to be doing both things: calling update() periodically, and having the flag set. That's all there's to it.

If you need a source of ticks for update(), you want the QQuickWindow::frameSwapped() or a similar signal. This gets emitted every frame, and exactly every frame. So, this would work:

QSGNode * myNode = ...;

QObject::connect(window, &QQuickWindow::frameSwapped, [=](){ myNode->update(); });
like image 162
Kuba hasn't forgotten Monica Avatar answered Nov 13 '22 07:11

Kuba hasn't forgotten Monica