З'єднання логіки з вашим інтерфейсом користувача QML

З'єднання модуля для виконання обчислень і надання інтерфейсу даних для показу

Щоб інтегрувати логіку до самої програми нам знадобляться класи модуля обробки мовою C++, які зможуть виконувати важливі обчислення. Не варто вписувати логіку до самих файлів QML — слід переносити якомога більшу її частину до модуля обробки, щоб код QML використовувався лише для показу інтерфейсу користувача — того, для чого його, власне, призначено.

Для нового класу модуля обробки створіть два файли із назвами backend.cpp і backend.h. Не забудьте додати нові файли cpp до модуля збирання виконуваного файла у src/CMakeLists.txt, поруч із main.cpp.

Додайте такі рядки до нового файла заголовків (backend.h):

#pragma once

#include <QObject>

class Backend : public QObject
{
    Q_OBJECT

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

Файл backend.cpp, який має містити визначення, так само зараз є порожнім. У ньому мають міститися десь такі рядки:

#include "backend.h"

Backend::Backend(QObject *parent)
    : QObject(parent)
{

}

На цей момент інтерфейсу користувача нічого не відомо про клас модуля обробки. Щоб повідомити про модуль, нам слід зареєструвати новий тип у main.cpp. Модуль обробки буде створено як одинак, що означає, що його буде створено лише одноразово і він існуватиме увесь час — від запуску програми до завершення її роботи.

Одразу після створення QQmlApplicationEngine, додайте реєстрацію типу до main.cpp ось так:

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

Не забудьте додати новий файл заголовків у початковій частині main.cpp.

З цього моменту у QML модуль обробки буде відомий як Backend. Він міститиметься у модулі із назвою org.kde.example. Оскільки модуль є частиною програми, вам не варто перейматися щодо встановлення його версій, просто лишіть версію 1.0 і використовуйте його послідовно у всій програмі.

У main.qml імпортуйте новий модуль:

import org.kde.example 1.0

Тепер клас, який містить майбутню логіку, з'єднано із програмою, але він усе ще не виконує ніяких корисних дій. Щоб змінити це, давайте додамо до класу властивість. Призначення властивостей є набагато ширшим за прості змінні. Вони можуть інформувати інтерфейс користувача щодо змін, щоб той міг оновлювати належні області.

Одразу після макроса Q_OBJECT додайте новий макрос Q_PROPERTY.

Q_PROPERTY(QString introductionText READ introductionText WRITE setIntroductionText NOTIFY introductionTextChanged)

Здається, забагато коду для простого читання і написання коду модуля обробки, чи не так? Але прискіпливіший погляд показує, що читання властивості з інтерфейсу вже може запускати логіку. Те саме стосується запису. У цьому випадку код автоматично інформує оболонку і модуль обробки про зміни.

Читання і запис засновано на концепції функцій отримання та встановлення значень, тому додайте новий закритий (приватний) атрибут, який міститиме дані, до вашого класу у описаний спосіб, а також додайте відповідні функції отримання та встановлення значень.

private:
    QString m_introductionText = "Hello World!";

У розділі public додайте

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

Перша функція є отримувачем даних, друга — встановлювачем, а третя — сигналом, який видається, коли змінюється значення властивості. Сигнал не потребує реалізації у файлі backend.cpp, оскільки він не виконує майже нічого, окрім видання, але функції отримання та встановлення значення має бути реалізовано десь так:

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

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

Як можна бачити, при виклику функції встановлення значення буде видано сигнал, отже про зміну буде проінформовано інтерфейс користувача і модуль обробки.

Щоб показати текст у main.qml додайте заголовок під властивістю title елемента Kirigami.Page, який вже міститься у шаблоні.

Код-результат у тій частині файла має виглядати ось так:

// ...
Kirigami.Page {
    title: i18n("develop.kde.org tutorial")

    Kirigami.Heading {
        anchors.centerIn: parent
        text: Backend.introductionText
    }

    actions: [
        Kirigami.Action {
            // ...
        }
    ]
}

Тепер зберіть і запустіть вашу програму знову.

Вітаємо, ви навчилися:

  • Як реєструвати типи модулів обробки у QML
  • Додавати нові елементи до файла QML
  • Створювати підкласи QObject
  • Як додавати властивості і для чого вони потрібні
  • Що таке сигнали

Якщо ви хочете дізнатися про інтеграцію між QML і C++, ми рекомендуємо ознайомитися із офіційною документацією до Qt.