[Development] How fast grab a QML item's content to image when it updates?
Denis Shienkov
denis.shienkov at gmail.com
Tue Dec 12 14:13:15 CET 2017
Hi all...
Is it possible to grab a QQuickItem content (e.g. with all sub-items)
when an item changes?
E.g. with widgets I use the following code:
bool MyWidget::event(QEvent *event)
{
if (event->type() == QEvent::UpdateRequest)
myGrab();
return QWidget::event(event);
}
void MyWidget::myGrab()
{
...
QBackingStore *store = backingStore();
Q_ASSERT(store);
QPaintDevice *pdev = store->paintDevice();
const auto image = dynamic_cast<QImage *>(pdev);
...
}
it is very fast (as I know)...
But with the QML I got a troubles: I can 'grab' the sourceItem, using
the FBO and private functions, but the fbo::toImage() is too slow (~24
msecs),
and I don't know how to intercept the signal when a watched item updates:
Grabber::Grabber(QQuickItem *parent)
: QQuickItem(parent)
{
setFlag(QQuickItem::ItemHasContents);
}
// Where sourceItem - is a watched item.
void Grabber::setSourceItem(QQuickItem *sourceItem)
{
if (sourceItem == m_sourceItem)
return;
m_sourceItem = sourceItem;
emit sourceItemChanged(m_sourceItem);
update();
}
QSGNode *Grabber::updatePaintNode(QSGNode *oldNode,
UpdatePaintNodeData *updatePaintNodeData)
{
Q_UNUSED(updatePaintNodeData);
if (!m_sourceItem)
return oldNode;
QSGRootNode root;
root.appendChildNode(QQuickItemPrivate::get(m_sourceItem)->itemNode());
const QScopedPointer<QSGRenderer> renderer(
QQuickItemPrivate::get(this)->
sceneGraphRenderContext()->createRenderer());
renderer->setRootNode(&root);
const QSize size(m_sourceItem->width(), m_sourceItem->height());
renderer->setDeviceRect(size);
renderer->setViewportRect(size);
renderer->setProjectionMatrixToRect(QRectF(QPointF(), size));
renderer->setClearColor(Qt::transparent);
QOpenGLFramebufferObject fbo(size);
renderer->renderScene(BindableFbo(&fbo));
fbo.release();
QElapsedTimer et;
et.start();
const QImage image = fbo.toImage(); // TOO LONG ~24 msec!
qDebug() << "Elapsed:" << et.elapsed();
return oldNode;
}
it is very fast (as I know).
But with the QML I got a troubles: I can 'grub' an item, using the FBO,
but the toImage() method is too slow (~24 msecs), and I don't know how
to intercept a signal when the watched item updates:
Grabber::Grabber(QQuickItem *parent)
: QQuickItem(parent)
{
setFlag(QQuickItem::ItemHasContents);
}
QSGNode *Grabber::updatePaintNode(QSGNode *oldNode,
UpdatePaintNodeData *updatePaintNodeData)
{
Q_UNUSED(updatePaintNodeData);
if (!m_sourceItem)
return oldNode;
QSGRootNode root;
root.appendChildNode(QQuickItemPrivate::get(m_sourceItem)->itemNode());
const QScopedPointer<QSGRenderer> renderer(
QQuickItemPrivate::get(this)->
sceneGraphRenderContext()->createRenderer());
renderer->setRootNode(&root);
const QSize size(m_sourceItem->width(), m_sourceItem->height());
renderer->setDeviceRect(size);
renderer->setViewportRect(size);
renderer->setProjectionMatrixToRect(QRectF(QPointF(), size));
renderer->setClearColor(Qt::transparent);
QOpenGLFramebufferObject fbo(size);
renderer->renderScene(BindableFbo(&fbo));
fbo.release();
QElapsedTimer et;
et.start();
const QImage image = fbo.toImage(); // TOO LONG!
qDebug() << "Elapsed:" << et.elapsed();
return oldNode;
}
More information about the Development
mailing list