Home > front end >  How to register QObject class in CMake with qt_add_qml_module?
How to register QObject class in CMake with qt_add_qml_module?

Time:02-20

I have a QObject derived class Expense that I use in QML like this.

// main.qml
Expense {
  id: expenseManager
  onExpenseCreated: {
      // Do something
  }
}

The expense class has no UI components, it has some basic Signal and Slots for API communications.

// expense.h

#ifndef EXPENSE_H
#define EXPENSE_H
#include <QObject>
#include <QString>

#include "service.h"

class Expense : public QObject
{
    Q_OBJECT

private:
    Service service;
    void networkError();
    bool buttonLock = false;

public:
    explicit Expense(QObject *parent = nullptr);


public slots:
    void createInvoice(QString item, float amount);

signals:
    void expenseCreated();

};

#endif // EXPENSE_H

I have used qmlRegisterType() for registering Expense type in QML. Below is how my main() looks like.

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


    qmlRegisterType<Expense>("com.kadbyte.expense", 1, 0, "Expense");

    ........
    return app.exec();
}

Everything working perfectly as it used to. But recently I have upgraded my project to QT6 with CMake as the build tool instead of QMake. In the docs I saw that we can use qt_add_qml_module command in CMakeList.txt to register C Classes instead of qmlRegisterType(), by adding QML_ELEMENT macro to the QObject class.

But I can't understand how to do this, the documentation doesn't make sense as it uses qmake example (Link to docs) instead of CMake. Below is my CMakeLists.txt file

cmake_minimum_required(VERSION 3.16)

project(Udyan VERSION 0.1 LANGUAGES CXX)

set(CMAKE_AUTOMOC ON)
set(CMAKE_CXX_STANDARD_REQUIRED ON)

find_package(Qt6 6.2 COMPONENTS Quick REQUIRED)

qt_add_executable(appUdyan
    main.cpp
    expense.h expense.cpp
)

qt_add_qml_module(appUdyan
    URI Udyan
    VERSION 1.0
    QML_FILES qml/main.qml
)

set_target_properties(appUdyan PROPERTIES
    MACOSX_BUNDLE_GUI_IDENTIFIER my.example.com
    MACOSX_BUNDLE_BUNDLE_VERSION ${PROJECT_VERSION}
    MACOSX_BUNDLE_SHORT_VERSION_STRING ${PROJECT_VERSION_MAJOR}.${PROJECT_VERSION_MINOR}
    MACOSX_BUNDLE TRUE
    WIN32_EXECUTABLE TRUE
)

target_compile_definitions(appUdyan
    PRIVATE $<$<OR:$<CONFIG:Debug>,$<CONFIG:RelWithDebInfo>>:QT_QML_DEBUG>)

target_link_libraries(appUdyan
    PRIVATE Qt6::Quick)

So how to use qt_add_qml_module to registering QObject class to use in QML?

Note: All the example I have given above is just an MRE and not my complete code.

CodePudding user response:

You just need to add QML_ELEMENT to your QObject-derived Expense class's header and make sure you have moc enabled in your CMakeLists.txt. In application case it doesn't matter if the expense.h/cpp sources are included via qt_add_executable or qt_add_qml_module. I think it's clearer to add them to qt_add_qml_module SOURCES. Then you just import module URI in you QML file. In the example below I'm printing out property value from Example object in QML.

CMakeLists.txt

set(CMAKE_AUTOMOC ON)

qt_add_qml_module(appUdyan
    URI udyan
    VERSION 1.0
    QML_FILES
        main.qml
    SOURCES
        expense.h
        expense.cpp
)

C

#include <QObject>
#include <QtQml/qqmlregistration.h>

class Expense : public QObject
{
    Q_OBJECT
    QML_ELEMENT
    Q_PROPERTY(int value READ value NOTIFY valueChanged)
public:
    explicit Expense(QObject *parent = nullptr);
    int value() const;

signals:
    void valueChanged();

private:
    int m_value {5};
};

QML:

import QtQuick
import udyan

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

    Expense {
        id: expense
        Component.onCompleted: console.log(expense.value)
    }
}
  • Related