QML:文档完全加载时触发的事件

QML: Event which triggers when document was completly loaded

我现在在开发一个应用程序 加载 QML 文件并制作 window 的屏幕截图。 这就是现在的样子:

QQmlApplicationEngine engine;
engine.loadData(data);
QQuickWindow *rootObject = qobject_cast<QQuickWindow *>(engine.rootObjects().first());

QImage image = rootObject->grabWindow();
image.save("window.png","PNG",90);

在这种情况下data只是简单的QML结构:

import QtQuick 2.3
import QtQuick.Window 2.2

Window {
    visible: true
    width: 360
    height: 360

    Text {
        anchors.centerIn: parent
        text: "Hello, world!"
    }
    MouseArea {
         anchors.fill: parent
         //onClicked: someSingleton.makeScreenshot();
    }
    Component.onCompleted: someSingleton.makeScreenshot();
}

但是我从 QQuickWindow::grabWindow() 得到的图像是空的,没有保存。所以我尝试通过 Component.onCompleted 以另一种方式实现它,但它仍然不起作用。 (someSingleton.makeScreenshot() 是一个像上面的代码一样调用 QQuickWindow::grabWindow() 的函数)。让它工作的唯一方法是在 window 完全加载时在 MouseArea .onClicked 中调用此函数。所以我得出结论,在第一次尝试的 2 次中,QML 树没有完全加载。

我也试过这个代码:

connect(rootObject,&QQuickWindow::afterRendering,[=] () {
    QImage image = rootObject->grabWindow();
    image.save("window.png","PNG",90);
});

但是程序的执行只是挂在第一行。

所以我的问题 - 当 QML 文档完全加载时是否会触发某些事件 ?

P.S。在实际应用程序中,我无法修改 QML 源代码,因此所有功能都必须在 C++ 部分。 Component.onCompletedMouseArea .onClicked这里只是为了测试目的.

我不确定为什么以下内容不起作用:

#include <QtQuick>
#include <QtGui>

class Object : public QObject
{
    Q_OBJECT
public slots:
    void save() {
        QQuickWindow *window = qobject_cast<QQuickWindow*>(sender());
        QImage image = window->grabWindow();
        image.save("window.png", "PNG", 90);
    }
};

int main(int argc, char *argv[])
{
    QGuiApplication app(argc, argv);
    QQmlApplicationEngine engine;

    QByteArray data = "import QtQuick 2.3\n"
        "import QtQuick.Window 2.2\n"
        "Window {\n"
            "visible: true\n"
            "width: 360\n"
            "height: 360\n"
            "Text {\n"
                "anchors.centerIn: parent\n"
                "text: \"Hello, world!\"\n"
            "}\n"
            "MouseArea {\n"
                 "anchors.fill: parent\n"
            "}\n"
        "}";
    engine.loadData(data);

    QQuickWindow *rootObject = qobject_cast<QQuickWindow *>(engine.rootObjects().first());

    Object object;
    QObject::connect(rootObject, SIGNAL(afterRendering()), &object, SLOT(save()));

    return app.exec();
}

#include "main.moc"

可能是用法不正确,或者实际上某处存在错误。我不确定。值得在邮件列表中询问,或者如果您不确定,请创建错误报告。

但是,如果您改用 frameSwapped(),它会起作用:

    QObject::connect(rootObject, SIGNAL(frameSwapped()), &object, SLOT(save()));

好的,经过长时间的搜索,我发现 solution.As 通常我只需要更仔细地阅读 Qt 文档。

QImage QQuickWindow::​grabWindow()

http://doc.qt.io/qt-5/qquickwindow.html#grabWindow

警告: 此函数只能从 GUI thread.

中调用
void QQuickWindow::​afterRendering()

http://doc.qt.io/qt-5/qquickwindow.html#afterRendering

警告: 此信号从 scene graph rendering thread.

发出

所以,slot是在场景图渲染线程中执行的,由于冲突挂掉了。我刚刚更改了上面的示例,以确保插槽按照 here.

所述在 GUI 线程中执行
connect(rootObject,&QQuickWindow::afterRendering,this,[=] () {
    QImage image = rootObject->grabWindow();
    image.save("window.png","PNG",90);
},Qt::QueuedConnection);