3

I have a QQuickWidget and want to grab a screenshot using QQuickWindow::grabWindow(). However when I do that the QQuickWindow becomes an image and is not responsive.

Below is a minimal reproducible code: The bug is reproducible in Qt5.13 to Qt5.15.1 in release mode (for some reason Qt throws an assert in debug)

//TestWidget.pro

QT       += core gui

greaterThan(QT_MAJOR_VERSION, 4): QT += widgets quickwidgets

CONFIG += c++11

# You can make your code fail to compile if it uses deprecated APIs.
# In order to do so, uncomment the following line.
#DEFINES += QT_DISABLE_DEPRECATED_BEFORE=0x060000    # disables all the APIs deprecated before Qt 6.0.0

SOURCES += \
    main.cpp \
    mainwindow.cpp

HEADERS += \
    mainwindow.h \
    windowgrabber.h

FORMS += \
    mainwindow.ui

# Default rules for deployment.
qnx: target.path = /tmp/$${TARGET}/bin
else: unix:!android: target.path = /opt/$${TARGET}/bin
!isEmpty(target.path): INSTALLS += target

DISTFILES += \
    Main.qml

RESOURCES += \
    qml.qrc

//main.cpp

#include <QApplication>
#include <QQuickWidget>
#include <QQmlContext>
#include "windowgrabber.h"

int main(int argc, char *argv[])
{
    QApplication a(argc, argv);

    QQuickWidget *quickWidget = new QQuickWidget;
    quickWidget->rootContext()->setContextProperty("windowGrabber", new WindowGrabber(quickWidget));
    quickWidget->setSource(QUrl("qrc:/Main.qml"));
    quickWidget->show();

    return a.exec();
}

//Main.qml

import QtQuick 2.0
import QtQuick.Controls 2.0

Page {
    Button {
        id: button
        text: "grab window"
        onClicked: windowGrabber.grabWindow(button)
    }
}

//WindowGrabber.h

#ifndef WINDOWGRABBER_H
#define WINDOWGRABBER_H

#include <QObject>
#include <QQuickItem>
#include <QQuickWindow>

class WindowGrabber : public QObject
{
    Q_OBJECT
public:
    WindowGrabber(QObject *parent = nullptr) : QObject(parent) {}
    Q_INVOKABLE static void grabWindow(QQuickItem *item) {
        item->window()->grabWindow();
    }
};

#endif // WINDOWGRABBER_H

The code creates a QQuickWidget with source set to Main.qml. I want to take a screenshot when the button inside the qml is clicked. But after clicking the button the QQuickWindow inside the quickwidget becomes an image and button also becomes an image. I have tested with QWidget::createWindowContainer and it works, but the best solution would be to use a QQuickWidget. Anyone have any clues to why this might happen?

scopchanov
  • 7,966
  • 10
  • 40
  • 68
SkySoft
  • 133
  • 7
  • My colleague wrote the original post but it got deleted. He asked me to rewrite the question on his behalf. I hope the wording makes the question clearer now. Sorry for any confusion – SkySoft Nov 09 '20 at 00:11
  • @eyllanesc he did not delete the question but it got deleted by the community because it was not reproducible so I rewrote the question as we cannot find a way to fix it. – SkySoft Nov 09 '20 at 00:16
  • @eyllanesc Yea his post was deleted by the community. It says "This post is hidden. It was automatically deleted yesterday by the community" – SkySoft Nov 09 '20 at 00:21
  • @eyllanesc https://stackoverflow.com/questions/64544449/why-calling-qquickwindowgrabwindow-on-a-qquickwidget-turns-the-entire-widget – SkySoft Nov 09 '20 at 00:23
  • @eyllanesc Thx for the info. I'm still learning the OS community so my post might seem imperfect. But we are trying to find an alternative solution and just hope someone might shed some left on this problem. – SkySoft Nov 09 '20 at 00:30
  • @SkySoft 1) If the community closes your post it is because it does not meet the expected quality (please read [ask], [answer] and pass the [tour]) so you are saying to yourself: "Take your time and improve your question to Through an edition ", as soon as you make your edition it will be launched for other members of the community to review and if it already complies with what is requested then it is likely to be reopened, so it works SO. – eyllanesc Nov 09 '20 at 00:34
  • @eyllanesc Ok I will keep that in mind, thanks – SkySoft Nov 09 '20 at 00:44

1 Answers1

2

QQuickWidget uses a non-visible QQuickWindow to render the items, and that rendering is rendered again in the QWidget, so when trying to save the image it interferes, causing the lag as I have already pointed out in this post.

A possible solution is to grab directly from the QQuickWidget:

#ifndef WINDOWGRABBER_H
#define WINDOWGRABBER_H

#include <QObject>
#include <QQuickWidget>

class WindowGrabber : public QObject
{
    Q_OBJECT
public:
    WindowGrabber(QQuickWidget *widget): m_widget(widget)  {}
    Q_INVOKABLE void grabWindow() {
        if(m_widget){
            QPixmap img = m_widget->grab();
            qDebug() << img;
        }
    }
private:
    QPointer<QQuickWidget> m_widget;
};


#endif // WINDOWGRABBER_H
#include <QApplication>
#include <QQuickWidget>
#include <QQmlContext>
#include "windowgrabber.h"

int main(int argc, char *argv[])
{
    QApplication a(argc, argv);

    QQuickWidget quickWidget;
    WindowGrabber grabber(&quickWidget);
    quickWidget.rootContext()->setContextProperty("windowGrabber", &grabber);
    quickWidget.setSource(QUrl("qrc:/main.qml"));
    quickWidget.show();

    return a.exec();
}
Button {
    id: button
    text: "grab window"
    onClicked: windowGrabber.grabWindow()
}
eyllanesc
  • 235,170
  • 19
  • 170
  • 241