На уровне класса 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, который указан в качестве метода получения значения свойства.