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

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

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

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

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

#pragma once

#include <QObject>

class Backend : public QObject
{
    Q_OBJECT

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

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

#include "backend.h"

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

}

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

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

    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 додайте

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

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

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

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

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

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

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

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

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

            actions {
                main: Kirigami.Action {
                    ...

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

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

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

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