1
votes

I just began learning about Qt programming and found myself struggling with the signals and slot mechanism while making a simple test application.

I have two QML files: main.qml and grocery.qml.

I have a header file that manages the signals and slots of the application:

applicationamanger.h

#ifndef APPLICATIONMANAGER_H
#define APPLICATIONMANAGER_H
#include <QObject>
#include <QDebug>
class ApplicationManager : public QObject
{
    Q_OBJECT
public:
    explicit ApplicationManager(QObject *parent = 0);

signals:
    void newGroceryItem();

public slots:
    void addGroceryItem();
};
#endif // APPLICATIONMANAGER_H

The user starts the application on main.qml and when pressing a button loads grocery.qml

On grocery.qml I have an image that can be clicked by the user and emits the signal newGroceryItem()

MouseArea {
    id: okBtnClkd
    anchors.fill: parent
    Connections {
        onClicked: {
            newGroceryItem()
        }
    }
}

And the main application main.cpp connects the signals but says it can't find the signal newGroceryItem() as it doesn't belong to main.qml. So my question is, how can I establish the connection to the slot addGroceryItem() from the secondary qml file grocery.qml?

EDIT: As requested here're the contents of main.cpp

#include <QGuiApplication>
#include <QQmlApplicationEngine>
#include <QQuickWindow>
#include <QQmlContext>
#include "applicationmanager.h"
int main(int argc, char *argv[]){
  QGuiApplication app(argc, argv);
  QQmlApplicationEngine engine;
  engine.load(QUrl(QStringLiteral("qrc:/main.qml")));

  QObject *topLevel = engine.rootObjects().value(0);
  QQuickWindow *window = qobject_cast<QQuickWindow *>(topLevel);
  ApplicationManager applicationManager;
  QObject::connect(window, SIGNAL(newGroceryItem()), &applicationManager, SLOT(addGroceryItem()));

  return app.exec();
}

And the contents of grocery.qml

import QtQuick 2.5
import QtQuick.Controls 1.4

ApplicationWindow {
    //Declaration of signals.
    signal newGroceryItem()

    width: 300
    height: 400
    visible: true
    TextField {
        id: product
        x: 14
        y: 111
        width: 270
        height: 22
    }
    Text {
        id: text1
        x: 14
        y: 81
        width: 124
        height: 24
        text: qsTr("Product")
        font.pixelSize: 20
    }
    Image {
        id: okBtn
        x: 99
        y: 290
        width: 100
        height: 100
        source: "img/main/okBtn.png"

        MouseArea {
            id: okBtnClkd
            anchors.fill: parent
            Connections {
                onClicked: {
                    newGroceryItem()
                }
            }
        }
    }
}
1
Please show your main.cpp and the entire grocery.qml (if it's large, please narrow it down to the minimum amount of code that reproduces the problem). - Mitch

1 Answers

0
votes

Any method of a QObject-derived type is accessible from QML code if it is:

  • a public method flagged with the Q_INVOKABLE macro
  • a method that is a public Qt SLOT

So there are two ways to access addGroceryItem(). The first one is to use Q_INVOKABLE macro as follows:

class ApplicationManager : public QObject
{
    Q_OBJECT
public:
    explicit ApplicationManager(QObject *parent = 0);
    Q_INVOKABLE void addGroceryItem();
};

The second way is to use public slots as follows:

class ApplicationManager : public QObject
{
    Q_OBJECT
public:
    explicit ApplicationManager(QObject *parent = 0);
public slots:
    void addGroceryItem();
};

If you are creating your class object in C++ then you should set the object as the context data for main.qml as follows:

 int main(int argc, char *argv[]) {
     QCoreApplication app(argc, argv);

     QQmlEngine engine;
     ApplicationManager app;
     engine.rootContext()->setContextProperty("applicationManager", &app);
     QQmlComponent component(&engine, QUrl::fromLocalFile("main.qml"));
     component.create();

     return app.exec();
 }

Now you can access the ApplicationManager object created in main.cpp from main.qml as follows:

MouseArea {
    id: okBtnClkd
    anchors.fill: parent
    onClicked: {
        applicationManager.addGroceryItem();
    }
}

For more information see here.