定期重新绘制QQuickItem

5
我通过扩展QQuickItem并重写updatePaintNode()函数创建了一个自定义的QML元素。由于我需要在时间线上绘制随着实时增长的矩形,因此需要在每个新帧中重新绘制GUI。
是否有一种方式可以使updatePaintNode()函数定期执行以便在每个新帧中重绘?
我曾尝试调用node->markDirty(QSGNode::DirtyForceUpdate),但此操作并未导致updatePaintNode()函数被定期调用。
编辑:这是我的代码示例:
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;
}

1
你一定做错了什么,确保代码在正确的节点上运行。它应该可以工作的。 - Kuba hasn't forgotten Monica
我把我的代码添加到了帖子中,也许你可以帮我解决问题! - user2052244
你需要设置QQuickItem :: ItemHasContents。你创建了一个定时器来定期调用update()吗? - Jay
1个回答

6
根据updatePaintNode的文档:

如果用户在项上设置了QQuickItem :: ItemHasContents标志,则在调用QQuickItem :: update()的结果下调用此函数。

你需要同时做两件事:定期调用update()并设置该标志。就是这样简单。
如果你需要一个update()的时钟源,你可以使用QQuickWindow::frameSwapped()或类似的信号。它会在每帧被发射,确保每帧都会被处理。所以可以这样做:
QSGNode * myNode = ...;

QObject::connect(window, &QQuickWindow::frameSwapped, [=](){ myNode->update(); });

为了每隔几秒钟调用update()函数,设置一个计时器似乎对我来说很麻烦,因此我认为应该有一种机制来处理流畅的重绘(即自动调用update()函数来绘制每一帧)。 - user2052244
奇怪的是,这个“frameSwapped”信号对我不起作用。当我的应用程序启动时,它被发射一次,场景被绘制,然后“update”再也没有被调用过。 - Aleksei Petrenko
1
如果我手动调用更新(update)也不起作用,尽管我将ItemHasContents设置为true。 - Aleksei Petrenko
1
在最近的Qt版本中,如果场景中没有任何需要处理的内容,它们可能已经优化了帧交换。您可以调查在updatePaintNode()内调用update()是否可行。也许它只会在下一帧中更新 - 这正是您所希望的。 - Kuba hasn't forgotten Monica
2
qtdeclarative/src/quick/scenegraph/qsgthreadedrenderloop.cpp的源代码中有一个字符串:"更新只能从GUI线程或QQuickItem :: updatePaintNode()调度"。 - Velkan

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接