Qt Quick — первая программа на QML
Qt Quick — интерфейс на QML (как разметка), логика на C++.
Соберём счётчик: кнопка "+1", подпись обновляется сама при изменении поля в C++.
Виджетный путь — Qt — первая программа.
CMake — CMake — первая программа.
Где применяют Qt Quick
Qt Quick — UI для анимаций, touch-экранов, встраиваемых панелей и единого интерфейса на desktop и устройстве. Классические формы Windows чаще на Qt Widgets (Qt — первая программа).
| Термин | Простыми словами |
|---|---|
| QML | язык описания интерфейса (объекты, привязки, анимации) |
| Qt Quick | модуль рантайма, который рисует QML-сцену |
| Q_PROPERTY | поле C++-объекта, видимое в QML |
| Привязка | выражение в QML пересчитывается при изменении данных |
| moc | генерирует метаданные для Q_OBJECT и свойств |
Два слоя — QML и C++
В Qt — первая программа кнопки создавали в C++. Здесь:
- QML — "как выглядит" (
Button,Label, отступы); - C++ — "что хранится и как считается" (
Counter,increment()).
Число живёт только в C++. QML читает counter.value и вызывает counter.increment() — без дублирования состояния.
Что мы строим
Окно: подпись "Значение: N", кнопка "+1". При клике N растёт, подпись обновляется без setText из C++.
Установка
В инсталляторе Qt 6 отметьте Qt Quick / Qt Declarative. Без него find_package(Qt6 COMPONENTS Quick) завершится ошибкой.
Структура проекта
qt-quick-hello/
├── CMakeLists.txt
├── main.cpp
├── counter.hpp
├── counter.cpp
└── qml/
└── Main.qml
| Часть | Назначение |
|---|---|
Counter | хранит value, сигнал valueChanged, метод increment() |
Main.qml | разметка, привязки к counter |
main.cpp | QGuiApplication, движок QML, setContextProperty |
qt_add_qml_module | упаковка QML в модуль HelloApp |
CMakeLists.txt
Код ITЗагрузка примера кода…
Разбор:
- CMake-конфиг настраивает сборку Qt Quick-приложения и подключает QML-модуль.
CMAKE_AUTOMOC ONобязателен для классов сQ_OBJECTи метаинформацией свойств.find_package(Qt6 ... Quick Qml)подключает runtime для QML-интерфейса и нужные библиотеки.qt_add_qml_moduleрегистрируетMain.qmlв модулеHelloApp, чтобы загружать его по URI.target_link_libraries(... Qt6::Quick)связывает исполняемый файл с графическим стеком Qt Quick.
qt_add_qml_module — Qt 6: CMake знает URI HelloApp для engine.loadFromModule("HelloApp", "Main").
cmake -S . -B build -DCMAKE_PREFIX_PATH="/path/to/Qt/6.x/gcc_64"
cmake --build build
Модель на C++ — Q_PROPERTY
Код ITЗагрузка примера кода…
Разбор:
- Класс
CounterнаследуетQObject, чтобы участвовать в метаобъектной системе Qt и быть видимым из QML. Q_PROPERTYобъявляет свойствоvalueс чтением, записью и сигналом изменения, на который подписывается интерфейс.setValueпроверяет, изменилось ли значение, и только потом вызываетemit valueChanged(), чтобы избежать лишних перерисовок.Q_INVOKABLE increment()открывает метод для вызова из QML (counter.increment()).- Поле
value_{0}хранит состояние в C++-модели, а QML-слой только отображает и триггерит действия.
Разбор строки Q_PROPERTY
Q_PROPERTY(int value READ value WRITE setValue NOTIFY valueChanged)
Разбор:
Q_PROPERTYсвязывает поле модели с QML и делает его частью рефлексии Qt.READ valueиWRITE setValueопределяют функции доступа к свойству с контролем инвариантов.NOTIFY valueChangedуказывает сигнал, по которому QML понимает, что нужно обновить привязанные выражения.- Без корректного
NOTIFYинтерфейс не будет автоматически отражать изменения данных. - Это основной механизм реактивности Qt Quick на стороне C++-кода.
| Фрагмент | Смысл |
|---|---|
int value | в QML свойство называется value, тип int |
READ value | читать через метод value() |
WRITE setValue | писать через setValue(int) (для двусторонних привязок) |
NOTIFY valueChanged | при изменении обязательно emit valueChanged() — QML обновит экран |
Q_INVOKABLE void increment() — метод, вызываемый из QML как counter.increment().
if (value_ == v) return — лишние сигналы не уходят в UI, меньше перерисовок.
counter.cpp может быть пустым, если вся логика в заголовке — для учебного примера нормально.
main.cpp — движок и контекст
Код ITЗагрузка примера кода…
Разбор:
main.cppсвязывает слой логики C++ и QML-слой интерфейса в единую программу.QGuiApplicationинициализирует графическую среду без набора виджетовQt Widgets.engine.rootContext()->setContextProperty("counter", &counter)публикует объектcounterв пространство имён QML.engine.loadFromModule("HelloApp", "Main")загружает корневой QML-компонент из модуля, объявленного в CMake.- Проверка
rootObjects().isEmpty()быстро ловит ошибки загрузки QML до старта event loop.
| Строка | Смысл |
|---|---|
QGuiApplication | GUI без набора Widgets — достаточно для Quick |
Counter counter | объект на стеке, живёт всё время main |
setContextProperty("counter", &counter) | в любом QML файле этого движка имя counter → наш объект |
loadFromModule("HelloApp", "Main") | загрузить корневой Main.qml из модуля CMake |
rootObjects().isEmpty() | проверка: QML загрузился (иначе смотреть вывод ошибок в консоль) |
В больших приложениях тип регистрируют через qmlRegisterType<Counter>() и создают Counter { } в QML. Для первого шага хватает контекста.
Main.qml — разбор
Код ITЗагрузка примера кода…
Разбор:
- QML-файл декларативно описывает окно, вертикальный контейнер и два элемента управления.
Label.textиспользует привязку кcounter.value, поэтому текст пересчитывается автоматически при изменениях модели.Button.onClickedвызывает метод C++-объекта, опубликованного через контекст движка.anchors.centerInиspacingотвечают за компоновку элементов без ручного расчёта координат.- Такой шаблон чётко разделяет роли: QML отвечает за отображение, C++ — за состояние и бизнес-логику.
Привязка в text
text: "Значение: " + counter.value
Это привязка, а не разовое присваивание:
- QML подписывается на
valueChanged(через метаданныеNOTIFY). - При
increment()→setValue→emit valueChanged()строка пересчитывается. Labelперерисовывается без вызова C++ API для текста.
Обработчик onClicked
onClicked: counter.increment()
onClicked — обработчик сигнала кнопки. Внутри — вызов C++-метода.
Как связаны C++ и QML
| Механизм | Когда использовать |
|---|---|
Q_PROPERTY + NOTIFY | поля на экране |
Q_INVOKABLE | действия по кнопке |
setContextProperty | один глобальный объект в прототипе |
qmlRegisterType | несколько экземпляров в QML |
Qt Widgets или Qt Quick?
| Qt Widgets | Qt Quick | |
|---|---|---|
| Описание UI | C++ (+ .ui) | QML |
| Типичные задачи | офис, IDE, нативные диалоги | анимации, touch, HMI |
| Старт | Qt — первая программа | эта статья |
Гибрид: QQuickWidget внутри окна на виджетах.
Частые ошибки
| Симптом | Вероятная причина |
|---|---|
| Белое окно | QML не загрузился — синтаксис, URI, qt_add_qml_module |
counter is undefined | нет setContextProperty или опечатка в имени |
| Счётчик не обновляется | нет NOTIFY или забыли emit valueChanged() |
| Сборка без QML | не подключён qt_add_qml_module |
Почему это масштабируется в реальных проектах
В небольшом примере есть та же архитектурная идея, что и в большом продукте:
- состояние живёт в модели (
Counter); - QML только отображает и отправляет команды;
- синхронизация между UI и данными идёт через сигналы изменений.
На этой основе строят формы, панели телеметрии, мультимедийные интерфейсы и HMI.
Связанные статьи
- Виджеты и классический UI: Qt — первая программа
- Общий обзор Qt-экосистемы: Qt - кроссплатформенный фреймворк на C++
- CMake и настройка сборки: CMake — первая программа
- Тестирование и практические задания: Google Test и Catch2 в C++, Практические задания по C++
Что попробовать
- Кнопка "Сброс" и
Q_INVOKABLE void reset() { setValue(0); }. qmlRegisterType<Counter>иCounter { id: c }вместо контекста.NumberAnimationна свойство в QML (чисто декларативно).
Тесты Counter без GUI — Google Test и Catch2 в C++. Практика — задание 4.2 в Практические задания по C++.
Дальше
windeployqtдля QML-зависимостей — Qt - кроссплатформенный фреймворк на C++;- Model/View для списков — там же;
- виджетный путь — Qt — первая программа.
В подборках
Статья входит в тематические подборки и блок "С чего начать?" на главной. Соседние шаги того же маршрута:
Первые шаги (маршрут подборки) — Qt — первая программа, Первая программа на Laravel, CMake — первая программа, Первая программа на Symfony, Razor Pages — первая программа, Ktor — первая программа.