Всем привет.
Когда то давно поднимал тему о том, как сграббить содержимое виджета
в картинку при изменении его содержимого, и мне помог Igors, примерно
с таким кодом:
C++ (Qt)
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);
...
}
Но теперь встала аналогичная задача с QML, нужно сграббить Item со всем его содержимым
в картинку каждый раз при его изменении. На LOR-е подсказали примерный код (https://www.linux.org.ru/forum/development/13426904?lastmod=1513085120141#comment-13886490), который я немного подправил:
C++ (Qt)
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;
}
но тут два косяка:
1. Оочень медленно работает fbo.toImage() - около 24 миллисекунд для 800х600
(и где хваленое OpenGL??).
2. Непонятно как узнать момент перерисовки содержимого отслеживаемого Item,
у него нету ну никаких сигналов.
Ппц, я уже закипел как чайник.. :(
В итоге набросал на коленке такой код (https://www.linux.org.ru/forum/development/13426904?lastmod=1513145148970#comment-13887658), но все-равно, кажется, что это какой-то костыль убогий и тормозной. :(