В первом материале мы создали минимальное Qt Quick-приложение и разобрались, как QML загружается из C++. Следующий логичный шаг — связать QML с C++-логикой: передать объект в QML, вызвать методы и получить данные.
В этой статье мы разберём:
- что такое QML context
- как передать C++-объект в QML
- как вызывать C++-методы из интерфейса
- какие ошибки совершают новички
Что такое QML Context
QML Context — это область видимости, в которой QML видит объекты и свойства из C++.
Проще говоря:
Context — это мост между C++ и QML.
Существует несколько способов экспорта C++ в QML:
setContextProperty()— просто и быстроqmlRegisterType()— масштабируемо- Singleton-объекты
- Модели (QAbstractItemModel)
В этой статье используем первый способ, как самый наглядный.
Создаём C++ backend-класс
Начнём с минимального объекта, который будет доступен из QML.
backend.h
#pragma once
#include <QObject>
class Backend : public QObject
{
Q_OBJECT
public:
explicit Backend(QObject *parent = nullptr);
Q_INVOKABLE QString message() const;
};
backend.cpp
#include "backend.h"
Backend::Backend(QObject *parent)
: QObject(parent)
{
}
QString Backend::message() const
{
return "Сообщение из C++ backend";
}
Ключевые моменты
QObject— обязателенQ_OBJECT— включает meta-object системуQ_INVOKABLE— делает метод доступным из QML
Регистрируем объект в QML-контексте
Теперь передадим экземпляр Backend в QML.
main.cpp
#include <QGuiApplication>
#include <QQmlApplicationEngine>
#include <QQmlContext>
#include "backend.h"
int main(int argc, char *argv[])
{
QGuiApplication app(argc, argv);
QQmlApplicationEngine engine;
Backend backend;
engine.rootContext()->setContextProperty("backend", &backend);
engine.load(QUrl(QStringLiteral("qrc:/qml/Main.qml")));
if (engine.rootObjects().isEmpty())
return -1;
return app.exec();
}
Теперь объект backend доступен глобально во всём QML.
Используем C++-объект в QML
Main.qml
import QtQuick 2.15
import QtQuick.Controls 2.15
ApplicationWindow {
visible: true
width: 400
height: 300
title: "QML ↔ C++"
Column {
anchors.centerIn: parent
spacing: 10
Text {
id: label
text: "Ожидание..."
}
Button {
text: "Вызвать C++"
onClicked: label.text = backend.message()
}
}
}
При нажатии кнопки QML вызывает C++-метод напрямую.
Добавляем свойства (Q_PROPERTY)
Методы — это хорошо, но QML лучше работает с реактивными свойствами.
Обновим backend.h
class Backend : public QObject
{
Q_OBJECT
Q_PROPERTY(QString status READ status NOTIFY statusChanged)
public:
explicit Backend(QObject *parent = nullptr);
QString status() const;
Q_INVOKABLE void updateStatus();
signals:
void statusChanged();
private:
QString m_status;
};
backend.cpp
Backend::Backend(QObject *parent)
: QObject(parent),
m_status("Стартовое состояние")
{
}
QString Backend::status() const
{
return m_status;
}
void Backend::updateStatus()
{
m_status = "Обновлено из C++";
emit statusChanged();
}
Использование свойства в QML
Text {
text: backend.status
}
Button {
text: "Обновить"
onClicked: backend.updateStatus()
}
Теперь QML автоматически обновляется при изменении данных в C++.
Возможные ошибки
Ошибка 1: забыли Q_OBJECT
→ QML не видит методы и свойства.
Ошибка 2: объект создан в стеке, но удалён раньше QML
→ приложение падает.
Ошибка 3: логика в QML вместо C++
→ сложность поддержки.
Ошибка 4: setContextProperty для больших проектов
→ лучше qmlRegisterType.
Итог
В этой статье мы:
- разобрали, что такое QML context
- передали C++-объект в QML
- вызвали C++-методы из интерфейса
- подключили реактивные свойства
