Conectar funcionalidad C++ con la interfaz QML

Desde QML puede acceder a cada "propiedad" definida en su funcionalidad ó código C++. El código QML final de acceso quedará:

Backend.introductionText

Otra forma de nombrar funcionalidad en otro ejemplo distinto podría ser:

Users.list

1. Añade el siguiente código a un nuevo archivo (KDevelop > File > New) y guardalo en tu aplicación MauiKit en myapp/src/code/backend.h:

#pragma once

#include <QObject>
#include <QDebug>

class Backend : public QObject
{
    Q_OBJECT
    Q_PROPERTY(QString introductionText READ introductionText WRITE setIntroductionText NOTIFY introductionTextChanged)

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

public:
    QString introductionText() const;
    void setIntroductionText(const QString &introductionText);
    Q_SIGNAL void introductionTextChanged();

private:
    QString m_introductionText;

private slots:
    void on_IntroductionTextChanged();
};

2. Añade la implementación a un nuevo archivo en myapp/src/code/backend.cpp:

#include "backend.h"

Backend::Backend(QObject *parent)
    : QObject(parent)
{
    connect(this, SIGNAL(introductionTextChanged()), this, SLOT(on_IntroductionTextChanged()));

    m_introductionText = "Hello World!";
}

QString Backend::introductionText() const
{
    return m_introductionText;
}

void Backend::setIntroductionText(const QString &introductionText)
{
    m_introductionText = introductionText;
    Q_EMIT introductionTextChanged();
}

void Backend::on_IntroductionTextChanged()
{
    qDebug() << "entra en slot";
}

3. Añade en main.cpp:

#include "backend.h"

4. Añade en main.cpp, justo después de la línea "QQmlApplicationEngine engine;":

Backend backend;
qmlRegisterSingletonInstance<Backend>("org.kde.myapp", 1, 0, "Backend", &backend);

5. Añade en myapp/src/CMakeLists.txt:

code/backend.cpp
set(project_SRCS
    code/main.cpp
    assets/assets.qrc
    code/backend.cpp
    )

No se confunda con myapp/CMakeLists.txt

El archivo correcto es myapp/src/CMakeLists.txt

6. Añada en el fichero qml en el que quiera acceder a la funcionalidad C++ el siguiente código.

Para establecer la conexión entre la funcionalidad C++ y la interfaz QML:

import org.kde.myapp 1.0

Para leer y escribir:

text: Backend.introductionText
Backend.introductionText = "Be happy"

En el siguiente ejemplo se añade a main.qml:

import QtQuick 2.15
import QtQuick.Controls 2.15
import org.mauikit.controls 1.3 as Maui
import org.kde.myapp 1.0

Maui.ApplicationWindow
{
    id: root

    Maui.Page {
        id: page

        anchors.fill: parent
        showCSDControls: true

        headBar.leftContent: ToolButton {
            icon.name: "typewriter"
            flat: true
            onClicked: {
                Backend.introductionText = "Be happy"
            }
        }

        Label {
            anchors.centerIn: parent
            text: Backend.introductionText
        }
    }
}

Pasar múltiples datos en una sola propiedad desde código C++ a la interfaz QML: QVariantList.

En el siguiente ejemplo se crea la propiedad "users" conteniendo "name", "surname", "active" y "age". La propiedad "users" será leída y escrita desde QML.

1. Sustituya el paso 1 y añada a myapp/src/code/backend.h

#pragma once

#include <QObject>
#include <QDebug>
#include <QVariantList>

class Backend : public QObject
{
    Q_OBJECT
    Q_PROPERTY(QVariantList users READ users WRITE setUsers NOTIFY usersChanged)

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

public:
    QVariantList users() const;
    void setUsers(const QVariantList &users);
    Q_SIGNAL void usersChanged();

private:
    QVariantList m_users;

private slots:
    void on_UsersChanged();
};

2. Sustituya el paso 2 y añada a myapp/src/code/backend.cpp

#include "backend.h"
#include <QVariantMap>

Backend::Backend(QObject *parent)
    : QObject(parent)
{
    connect(this, SIGNAL(usersChanged()), this, SLOT(on_UsersChanged()));

    QVariantMap user1;
    user1["name"] = "John";
    user1["subname"] = "Candy";
    user1["active"] = "false";
    user1["age"] = 43;

    QVariantMap user2;
    user2["name"] = "Errol";
    user2["subname"] = "Flynn";
    user2["active"] = "false";
    user2["age"] = 50;

    m_users.append(user1);
    m_users.append(user2);
}

QVariantList Backend::users() const
{
    return m_users;
}

void Backend::setUsers(const QVariantList &users)
{
    m_users = users;
    Q_EMIT usersChanged();
}

void Backend::on_UsersChanged()
{
    qDebug() << "entra en slot: user changed";
}

En una programación más realista sería parecido a esto:

for (int i = 0; i < max; i++) {
    QVariantMap user;
    user["name"] = data1[i];
    user["active"] = data2[i];
    m_users.append(user);
}

3. Sustituya el paso 6 y añada a main.qml:

import QtQuick 2.15
import QtQuick.Controls 2.15
import org.mauikit.controls 1.3 as Maui
import org.kde.myapp 1.0

Maui.ApplicationWindow
{
    id: root

    Maui.Page {
        id: page

        anchors.fill: parent
        showCSDControls: true

        headBar.leftContent: ToolButton {
            icon.name: "typewriter"
            flat: true
            onClicked: {
                var users = Backend.users
                users[0].name = "Johnny"
                Backend.users = users
            }
        }

        Label {
            id: label
            anchors.centerIn: parent
            text: Backend.users[0].name
        }
    }
}

Para leer desde C++ el objeto QVariantList "users" y acceder a la información de cada usuario puede usar el siguiente código donde desee. En este caso en la función de respuesta a usuario cambiado:

void Backend::on_UsersChanged()
{
    qDebug() << "entra en slot: user changed";

    QVariantMap user = m_users[0].toMap();
    QString name = user["name"].toString();

    qDebug() << name;
}

La salida de consola de KDevelop muestra (iniciar ejecución pulsando click sobre botón Debug):

entra en slot: user changed
"Johnny"

Invocar funciones C++ desde QML.

La macro Q_INVOKABLE permite invocar una función C++ desde código de interfaz QML.

1. Añade en myapp/src/code/backend.h:

public:
    Q_INVOKABLE void setOption(QString option);

2. Añade en myapp/src/code/backend.cpp:

void Backend::setOption(QString option)
{
    qDebug() << option;
}

3. Añade en main.qml:

headBar.leftContent: ToolButton {
    icon.name: "configure"
    flat: true
    onClicked: {
        Backend.setOption("option 1")
    }
}

Last updated