На уровне класса C++ также можно определить свойства, к которым можно будет установить привязку в коде QML. Благодаря механизму сигналов приложение получит уведомление о том, что изменилось значение свойства класса и обновит все привязанные свойства других элементов.
Для создания свойства в коде C++ применяется макрос Q_PROPERTY, который имеет следующий синтаксис:
Q_PROPERTY(тип_свойства имя_свойства READ метод_получения WRITE метод_изменения NOTIFY сигнал_изменения)
Определение свойства состоит из ряда компонентов. Вначале указывается тип и имя свойства. Затем после слова READ указывается метод, который возвращает значение свойства. После слова WRITE указывается метод, который изменяет значение свойства. В конце после слова NOTIFY указывается сигнал, который генерируется при изменении значения свойства.
Например, пусть в проекте определен класс Counter, код которого состоит из заголовочного файла counter.h и файла с реализацией counter.cpp:
В заголовочном файле counter.h определим следующий код:
#ifndef COUNTER_H #define COUNTER_H #include <QObject> class Counter: public QObject { Q_OBJECT Q_PROPERTY(int count READ getValue WRITE setValue NOTIFY valueChanged) public: Counter(QObject *parent = nullptr){} int getValue() const; void setValue(int newValue); Q_INVOKABLE void decrease(); Q_INVOKABLE void increase(); signals: void valueChanged(int); private: int value{}; }; #endif // COUNTER_H
Класс Counter наследуется от QObject и применяет макрос Q_OBJECT, благодаря чему класс может определять сигналы.
Далее идет макрос Q_PROPERTY, который указывает, что определяется свойство, которое называется "count" и имеет тип int. Для чтения этого свойства предназначен метод getValue, а для изменения его значения - метод setValue, в который передается новое значение. Для уведомления системы об изменении значения свойства применяется сигнал valueChanged.
В классе определено приватное свойство value, в котором хранится некоторое значение объекта Counter. Также в дополнение к методам getValue()/setValue() определено два метода - increase и decrease, которые будут изменять значение value. Благодаря макросу Q_INVOKABLE эти методы можно вызывать из кода QML.
В файле counter.cpp определим реализацию методов:
#include "counter.h" void Counter::increase() { setValue(value+1); } void Counter::decrease() { if(value > 0) setValue(value-1); } int Counter::getValue() const { return value; } void Counter::setValue(int newValue) { value = newValue; emit valueChanged(value); }
Методы increase и decrease, вызывают метод setValue, который увеличиваетт или уменьшает значение value на 1 и генерирует сигнал valueChanged, передавая в него обновленное значение.
В файле main.cpp зарегистрируем тип Counter:
#include <QGuiApplication> #include <QQmlApplicationEngine> #include "counter.h" int main(int argc, char *argv[]) { QGuiApplication app(argc, argv); QQmlApplicationEngine engine; // регистрация типа Counter qmlRegisterType<Counter>("counter", 1, 0,"Counter"); const QUrl url("qrc:/path/main.qml"); engine.load(url); return app.exec(); }
Используем тип Counter в файле main.qml:
import QtQuick import QtQuick.Controls import counter Window { width: 250 height: 150 visible: true title: "METANIT.COM" Counter{ id: counter} Row{ spacing: 10 anchors.centerIn: parent Button { text: "+" width: 30 height: 30 onClicked: counter.increase() } Text{ text: counter.count } Button { text: "-" width: 30 height: 30 onClicked: counter.decrease() } } }
Здесь определен элемент Counter с идентификатором counter, с которым будут взаимодействовать другие элементы. В частности, здесь также определены две кнопки, по нажатию на которые будут вызываться методы increase и decrease объекта counter.
Для вывода значения свойства count определен элемент Text, текст которого привязан к свойству count:
Text{ text: counter.count }
При этом нам не надо устанавливать явным образом обработчик сигнала valueChanged для объекта Counter. При изменении значения value в Counter система получит соответствующее увеломление и автоматически изменит привязанное свойство - свойство text элемента Text
Причем нам не надо явным образом вызывать методы increase/decrease или даже setValue для изменения поля value. Мы можем напрямую присвоить свойству count новое значение:
import QtQuick import QtQuick.Controls import counter Window { width: 250 height: 150 visible: true title: "METANIT.COM" Counter{ id: counter} Row{ anchors.centerIn: parent Button { text: "+" width: 30 height: 30 onClicked: counter.count+=5 } Text{ text: counter.count } Button { text: "-" width: 30 height: 30 onClicked: counter.count-=5 } } }
Здесь не вызывается явным образом никаких методов класса Counter, мы работаем со свойством count, как с обычным полем класса:
onClicked: counter.count += 5
Однако поскольку при определении свойства в классе Counter мы указали в качестве метода изменения метод setValue, то при любых присвоениях свойству count любых значений будет неявно вызываться метод setValue, в который через параметр будет передаваться присваиваемое свойству значение.
Равным образом, когда мы получаем значение свойства count:
text: counter.count
будет неявным образом срабатывать метод getValue, который указан в качестве метода получения значения свойства.