hannah
hannah

Reputation: 1

Connecting QML to C++ slot

I created an application taking automated screenshots each time the source of a loader is changing! I am trying to connect QML signal (screenshot()) to a CPP slot (take_screenshot()). However, take_screenshot() function is never been called although the source of the loader is beeing changed and I am receiving the console log as well! Here is my cpp.h

 class MyClass : public QObject
 {
    Q_OBJECT
public:
MyClass(std::shared_ptr<QQmlApplicationEngine> engin)
    : m_engine(engin)
{
    QObject* root = m_engine->rootObjects()[0];
    Q_ASSERT(root != nullptr);
    QObject::connect(root, SIGNAL(screenshot()),
                     this, SLOT(take_screenshot()));
}

public slots:
int take_screenshot()
{
        QString currentDateTime = QDateTime::currentDateTime().toString( "MMMM d, yyyy, HH:mm:ss");
        QScreen *screen;
        QPixmap pixmap;
        screen = QGuiApplication::primaryScreen();
        pixmap = screen->grabWindow(0);
        QString screenshotPath = QDir::currentPath();
        QString screenShotFileName = QString("%1/%2.png").arg(screenshotPath).arg(currentDateTime);

        if (!screenShotFileName.isEmpty())
        {
            pixmap.save(screenShotFileName);
            return 1;
        }
        else
            return 0;
}

private:
std::shared_ptr<QQmlApplicationEngine> m_engine;
};

And here is my main.qml

Window {
id: mainWindow
visible: true
width: 640
height: 480
title: qsTr("Hello World")

signal screenshot()
Loader {
         id: pageLoader
         objectName: "pageLoader"
         anchors.fill: parent
         onSourceChanged: {
         console.log("onSourceChanged_source :", pageLoader.source)
                mainWindow.screenshot()
            }
         Component.onCompleted:{
                console.log("onCompleted!", pageLoader.source)
                mainWindow.screenshot()
            }
        }
   }

Upvotes: 0

Views: 152

Answers (1)

eyllanesc
eyllanesc

Reputation: 243897

Do not access QML objects in C++ as you may get unexpected behaviors. In this case it is better to export the object to QML, for example create a singleton:

utils.h

#ifndef UTILS_H
#define UTILS_H

#include <QGuiApplication>
#include <QObject>
#include <QPixmap>
#include <QQmlApplicationEngine>
#include <QScreen>
#include <QDateTime>
#include <QDir>

class Utils : public QObject
{
    Q_OBJECT
public:
    using QObject::QObject;
public slots:
    bool screenshot(){
        qDebug() << __PRETTY_FUNCTION__;
        QString currentDateTime = QDateTime::currentDateTime().toString( "MMMM d, yyyy, HH:mm:ss");
        QString screenshotPath = QDir::currentPath();
        QString filename = QString("%1/%2.png").arg(screenshotPath).arg(currentDateTime);
        if(QScreen *screen = QGuiApplication::primaryScreen()){
            QPixmap pixmap = screen->grabWindow(0);
            return pixmap.save(filename));
        }
        return false;
    }
};
#endif // UTILS_H

main.cpp

#include "utils.h"

#include <QGuiApplication>
#include <QQmlApplicationEngine>


int main(int argc, char *argv[])
{
#if QT_VERSION < QT_VERSION_CHECK(6, 0, 0)
    QCoreApplication::setAttribute(Qt::AA_EnableHighDpiScaling);
#endif

    QGuiApplication app(argc, argv);

    QScopedPointer<Utils> utils(new Utils);
    qmlRegisterSingletonInstance("Utils", 1, 0, "Utils", utils.get());

    QQmlApplicationEngine engine;

    const QUrl url(QStringLiteral("qrc:/main.qml"));
    QObject::connect(&engine, &QQmlApplicationEngine::objectCreated,
                     &app, [url](QObject *obj, const QUrl &objUrl) {
        if (!obj && url == objUrl)
            QCoreApplication::exit(-1);
    }, Qt::QueuedConnection);
    engine.load(url);
    return app.exec();
}

main.qml

import QtQuick 2.15
import QtQuick.Window 2.15

import Utils 1.0

Window {
    id: mainWindow
    visible: true
    width: 640
    height: 480
    title: qsTr("Hello World")
    Loader {
        id: pageLoader
        anchors.fill: parent
        onSourceChanged: {
            console.log("onSourceChanged_source :", pageLoader.source)
            Utils.screenshot()
        }
        Component.onCompleted:{
            console.log("onCompleted!", pageLoader.source)
            var res = Utils.screenshot()
            console.log(res)
        }
    }
}

Upvotes: 1

Related Questions