З'єднання логіки з вашим інтерфейсом користувача 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.