1

I'm having a problem when I try to use Item::grabToImage() qml method. No matter which item I point to, it always says the following error:

grabToImage: item's window is not visible

I tried using the root/toplevel Item named rect too, but it didnt work.

My goal: I want to capture a rectangle sized image with the map tile and polygon draw on it

Below there's a minimal reproducible example

import QtQml 2.2
import QtLocation 5.9
import QtPositioning 5.9
import QtQuick 2.0
import QtQuick.Controls 2.4

Item {
    id: rect
    width: 1024
    height: 768

    visible: true

    Plugin {
        id: mapPlugin
        name: "osm"
    }

    Map {
        id: map
        enabled: true
        visible: true
        parent: rect
        gesture.enabled: true
        anchors.fill: parent
        plugin: mapPlugin
        zoomLevel: 14
        activeMapType: supportedMapTypes[3]
    }

    Item {
        anchors.bottom: parent.bottom
        anchors.left: parent.left
        anchors.right: parent.right
        anchors.margins: 10
        height: 40

        Button {
            id: saveToDisk
            text: qsTr("Pick")
            onClicked: {
                map.grabToImage(function (result) {
                    console.log('saving to disk..')
                    result.saveToFile("pick.png")
                })
            }
        }
    }
}
#include <QApplication>
#include <QQmlApplicationEngine>
#include <QtQuickWidgets/QQuickWidget>

int main(int argc, char *argv[])
{
    QCoreApplication::setAttribute(Qt::AA_EnableHighDpiScaling);

    QApplication app(argc, argv);

    QQuickWidget *q = new QQuickWidget;
    q->setResizeMode(QQuickWidget::SizeRootObjectToView);
    q->setSource(QUrl("main.qml"));
    q->show();

    return app.exec();
}
eyllanesc
  • 235,170
  • 19
  • 170
  • 241

1 Answers1

1

The strategy of QQuickWidget for painting is to create an off-screen QQuickWindow that renders the QML from where a screenshot is taken and drawn onto the widget. The above limits the use of grabToImage() since this method requires that the QQuickWindow of the items be visible.

The solution is to use QQuickView + QWidget::createWindowContainer():

#include <QApplication>
#include <QWidget>
#include <QQuickView>

int main(int argc, char *argv[])
{
    QCoreApplication::setAttribute(Qt::AA_EnableHighDpiScaling);

    QApplication app(argc, argv);

    QQuickView *q = new QQuickView;
    q->setResizeMode(QQuickView::SizeRootObjectToView);
    q->setSource(QUrl("main.qml"));

    QWidget * container = QWidget::createWindowContainer(q);
    container->show();

    return app.exec();
}
eyllanesc
  • 235,170
  • 19
  • 170
  • 241
  • Solution works flawless. But I have one more question: Would be possible to render the whole qml source file but have the qquickwindow not visible? I noticed theres a topic related to this: https://stackoverflow.com/questions/17146747/capture-qml-drawing-buffer-without-displaying Is that solution possible? What would be the best way to achieve this? What I need is to perform background tasks with QML, like rendering a map, and taking screenshots of map portions (rectangles). – Alex Soletti Dec 27 '19 at 16:36
  • Ok, thought I could ask here as this is more a personal question. – Alex Soletti Dec 27 '19 at 16:41
  • @AlexSoletti Personal? I don't think the question is personal. Your question(record some part of QML in off-screen) is far from your original question(record an item that is rendered within QQuickWidget), so it is recommended that you create another question so that more members of the community could help you. – eyllanesc Dec 27 '19 at 16:43
  • https://stackoverflow.com/questions/59503641/render-qml-without-being-visible-like-a-background-task New question here, ty – Alex Soletti Dec 27 '19 at 16:44