![Qt Software / [Из песочницы] QML и C++. Простой пример связки image](https://www.pvsm.ru/images/23cbe3fc1f2bb5d1e7a898abd3512128.jpg)
QML технология красивая и радует глаз. Меня она очень заинтересовала, и я решил ее освоить. Но не тут то было, ибо я оказался тупым и беспомощным. Нигде в сети не нашел примера «для чайников» (наверно плохо искал), чтобы с нуля построить простейшее приложение QML и C++ в связке. Везде чего-то не хватало: или не учитывался Qt Creator, или код выдавал ошибки, или отсутствовали целые моменты, которые пользователи должны были сами знать. Официальная документация и примеры здесь на хабре также были с этими недостатками. Вот и решил после долгих попыток и ошибок написать такую статью для начинающих с подробнейшим описанием.
Задача. Нужно написать программу QML в связке с С++, где
1. На форме располагается кнопка, строка ввода, и поле вывода.
2. Требуется считать из строки ввода число, прибавляется 1, и ответ выводится в поле вывода.
3. Интерфейс написан на QML.
4. Функционал на С++, то есть нам нужно обеспечить взаимосвязь между QML и C++: кнопка QML вызывает С++ функцию, а функция меняет свойства QML объектов.
Создание базового приложение QML
Используем Qt Creator. Я использовал версию 2.3 с Qt 4.7.4
Создание QML приложения
1. Создаем GUI Приложение: Файл -> Новый файл или проект.... Там слева выбираем Проект Qt Widget, с справа GUI приложение Qt. Потом жмем внизу кнопку "Выбрать...".
![Qt Software / [Из песочницы] QML и C++. Простой пример связки Qt Software / [Из песочницы] QML и C++. Простой пример связки](https://www.pvsm.ru/images/c5e9a3d0dd77fdd621fbd715f5593a44.png)
2. В следующем окне выбираем название нашего проекта (без пробелов и русских букв). Например, в нашем случае это "Example".
![Qt Software / [Из песочницы] QML и C++. Простой пример связки Qt Software / [Из песочницы] QML и C++. Простой пример связки](https://www.pvsm.ru/images/1dc12e1177007dd9f37cc3fb9b9d0200.png)
3. В следующем окне у Вас должна стоять галочка у "Desktop". Если ее у Вас ее нет, то Вы неверно установили Qt Creator (или Вы намерено не хотите создавать десктопные приложения). Та сборка Qt Creator официальная, которую я ставил (2.3), по умолчанию почему-то десктопные части не устанавливала.
![Qt Software / [Из песочницы] QML и C++. Простой пример связки Qt Software / [Из песочницы] QML и C++. Простой пример связки](https://www.pvsm.ru/images/dbaa5948836299b0d3312ca1766d54b5.png)
4. В следующем окне снимите галочку с пункта "Создать форму".
![Qt Software / [Из песочницы] QML и C++. Простой пример связки Qt Software / [Из песочницы] QML и C++. Простой пример связки](https://www.pvsm.ru/images/53ace1d59e398fed3bf98ed09072637c.png)
5. В следующем окне можно ничего не менять. И жмем кнопку "Завершить".
![Qt Software / [Из песочницы] QML и C++. Простой пример связки Qt Software / [Из песочницы] QML и C++. Простой пример связки](https://www.pvsm.ru/images/19e7c5e37f52ac23ecc0ed649a029c80.png)
Редактирование файла проекта
6. Отредактируем файл проекта (у нас это Example.pro):
И добавим к строчке "QT += core gui" слово "declarative". В итоге получим строчку:
QT += core gui declarative
Создание QML проекта
7. По папке с проектом в Qt Creator щелкаем правой кнопкой и идем к пункту "Добавить новый..."
![Qt Software / [Из песочницы] QML и C++. Простой пример связки Qt Software / [Из песочницы] QML и C++. Простой пример связки](https://www.pvsm.ru/images/e8336e5eefc7d293a0257cd926a05076.png)
8. Выбираем слева "QML", а справа "Файл QML".
![Qt Software / [Из песочницы] QML и C++. Простой пример связки Qt Software / [Из песочницы] QML и C++. Простой пример связки](https://www.pvsm.ru/images/8643f98875a5de33a4cda9a59a28638c.png)
9. Назовем его "main".
![Qt Software / [Из песочницы] QML и C++. Простой пример связки Qt Software / [Из песочницы] QML и C++. Простой пример связки](https://www.pvsm.ru/images/e6bcf86510027fb684c81282485677af.png)
10. Следующее окно без изменений.
![Qt Software / [Из песочницы] QML и C++. Простой пример связки Qt Software / [Из песочницы] QML и C++. Простой пример связки](https://www.pvsm.ru/images/b10de90105c650938fe537926ab53130.png)
11. В результате получим файл "main.qml" с текстом:
import QtQuick 1.0 Rectangle { width: 100 height: 62 }
Создаем файл ресурсов
12. По папке с проектом в Qt Creator щелкаем правой кнопкой и идем к пункту "Добавить новый..."
![Qt Software / [Из песочницы] QML и C++. Простой пример связки Qt Software / [Из песочницы] QML и C++. Простой пример связки](https://www.pvsm.ru/images/d802090eec475944e1470eddb69f8d22.png)
13. Выбираем слева "Qt", а справа "Файл ресурсов Qt".
![Qt Software / [Из песочницы] QML и C++. Простой пример связки Qt Software / [Из песочницы] QML и C++. Простой пример связки](https://www.pvsm.ru/images/9f9c3884b328bee63931af06a94264f6.png)
14. Назовем его "res".
![Qt Software / [Из песочницы] QML и C++. Простой пример связки Qt Software / [Из песочницы] QML и C++. Простой пример связки](https://www.pvsm.ru/images/fc20522fd4c753b655fec6447f643dcd.png)
15. Следующее окно без изменений.
![Qt Software / [Из песочницы] QML и C++. Простой пример связки Qt Software / [Из песочницы] QML и C++. Простой пример связки](https://www.pvsm.ru/images/7d1d2baea9ad38fbc284334267fa8e89.png)
В результате получим файд "res.qrc"
16. Добавим префикс. Для этого щелкнем по кнопке "Добавить", а там щелкнуть "Добавить префикс".
![Qt Software / [Из песочницы] QML и C++. Простой пример связки Qt Software / [Из песочницы] QML и C++. Простой пример связки](https://www.pvsm.ru/images/1a7fbf5d0eab5141ceb2ac741660d5db.png)
17. Измените текст префикса на "/".
![Qt Software / [Из песочницы] QML и C++. Простой пример связки Qt Software / [Из песочницы] QML и C++. Простой пример связки](https://www.pvsm.ru/images/87b628088c3367d92c2bf073a18ca26b.png)
18. Добавим наш QML файл. Для этого щелкнем по кнопке "Добавить", а там щелкнуть "Добавить файлы".
![Qt Software / [Из песочницы] QML и C++. Простой пример связки Qt Software / [Из песочницы] QML и C++. Простой пример связки](https://www.pvsm.ru/images/2e01cae07d07af0b8ebc0a6d450f508d.png)
19. И выберем наш файл "main.qml". И файл добавится к ресурсам нашего приложения:
![Qt Software / [Из песочницы] QML и C++. Простой пример связки Qt Software / [Из песочницы] QML и C++. Простой пример связки](https://www.pvsm.ru/images/06e5c9043a3f74404fd0607f8df180ba.png)
Если сейчас запустим наше приложение, то qml пока не увидим:
![Qt Software / [Из песочницы] QML и C++. Простой пример связки Qt Software / [Из песочницы] QML и C++. Простой пример связки](https://www.pvsm.ru/images/2eb59d23327fa84c649bbc5dbfff58c4.png)
Редактирование исходников
Теперь займемся подключением qml, чтобы он заработал.
20. Перейдем к редактированию файла "mainwindow.h" (находится в заголовочных). Он имеет пока вид:
#ifndef MAINWINDOW_H #define MAINWINDOW_H #include <QtGui/QMainWindow> class MainWindow : public QMainWindow { Q_OBJECT public: MainWindow(QWidget *parent = 0); ~MainWindow(); }; #endif // MAINWINDOW_H
Поменяем его на такой вид:
#ifndef MAINWINDOW_H #define MAINWINDOW_H #include <QMainWindow> #include <QtDeclarative/QDeclarativeView> #include <QGraphicsObject> #include <QtGui> #include <QDeclarativeContext> namespace Ui { class MainWindow; } class MainWindow : public QMainWindow { Q_OBJECT public: explicit MainWindow(QWidget *parent = 0); ~MainWindow(); private: QDeclarativeView *ui; }; #endif // MAINWINDOW_H
Мы добавили #include <QtDeclarative/QDeclarativeView>, #include <QGraphicsObject> и др, добавили namespace, добавили ключевое слово explicit, и главное добавили QDeclarativeView *ui.
21. Теперь займемся редактированием файла mainwindow.cpp. Он имеет пока вид:
#include "mainwindow.h" MainWindow::MainWindow(QWidget *parent) : QMainWindow(parent) { } MainWindow::~MainWindow() { }
Поменяем на такой:
#include "mainwindow.h" MainWindow::MainWindow(QWidget *parent) : QMainWindow(parent) { //Включаем наш QML ui = new QDeclarativeView; ui->setSource(QUrl("qrc:/main.qml")); setCentralWidget(ui); ui->setResizeMode(QDeclarativeView::SizeRootObjectToView); } MainWindow::~MainWindow() { //Удаляем QML delete ui; }
22. Запускаем наше приложение и получаем белое окно. Наш QML заработал.
![Qt Software / [Из песочницы] QML и C++. Простой пример связки Qt Software / [Из песочницы] QML и C++. Простой пример связки](https://www.pvsm.ru/images/a949e8958268f20659df3a9da09fe357.png)
Написание приложения
Теперь мы можем перейти к написанию непосредственно приложения, которое будет решать нашу задачу.
Построение интерфейса.
23. На данный момент main.qml выглядит так:
import QtQuick 1.0 Rectangle { width: 100 height: 62 }
![Qt Software / [Из песочницы] QML и C++. Простой пример связки Qt Software / [Из песочницы] QML и C++. Простой пример связки](https://www.pvsm.ru/images/47f3915eeafc6010a7f9b057cd93a2fd.png)
Отредактируем его, изменив главный прямоугольник-окно:
import QtQuick 1.0 //Главное окно Rectangle { width: 300 height: 300 anchors.fill: parent }
24. Добавим простейшую кнопку на нашу форму.
//Кнопка Rectangle { id: button //Имя кнопки //Размещаем в центре x: parent.width / 2 - button.width / 2; y: parent.height / 2 - button.height / 2; //Размеры кнопки width: 100 height: 30 //Цвет кнопки color: "gray" //Текст кнопки Text { id: buttonLabel text: "Пуск" anchors.centerIn: parent; } //Действие мыши MouseArea { anchors.fill: parent id: mouseArea } }
В результате main.qml примет вид:
import QtQuick 1.0 Rectangle { width: 300 height: 300 anchors.fill: parent //Кнопка Rectangle { id: button //Имя кнопки //Размещаем в центре x: parent.width / 2 - button.width / 2; y: parent.height / 2 - button.height / 2; //Размеры кнопки width: 100 height: 30 //Цвет кнопки color: "gray" //Текст кнопки Text { id: buttonLabel text: "Пуск" anchors.centerIn: parent; } //Действие мыши MouseArea { anchors.fill: parent id: mouseArea } } }
Если мы запустим приложение,
![Qt Software / [Из песочницы] QML и C++. Простой пример связки Qt Software / [Из песочницы] QML и C++. Простой пример связки](https://www.pvsm.ru/images/d01d75b902ddc94a51eedc6942f5ad70.png)
то получим следующее:
![Qt Software / [Из песочницы] QML и C++. Простой пример связки Qt Software / [Из песочницы] QML и C++. Простой пример связки](https://www.pvsm.ru/images/d436f6eeba16a4151371c9881828aab3.png)
25. Добавим строку ввода, куда пользователь будет вводить информацию с именем textinput.
//Строка ввода Rectangle { id: textinputRect //Имя строки ввода //Размещаем ниже x: parent.width / 2 - button.width / 2; y: parent.height / 2 - button.height / 2+40; //Размеры строки ввода width: 100 height: 18 //цвет строки ввода color: "gray" TextInput { id: textinput objectName: "textinput" color: "#151515"; selectionColor: "blue" font.pixelSize: 12; width: parent.width-4 anchors.centerIn: parent focus: true text:"1" } }
В результате main.qml примет вид:
import QtQuick 1.0 Rectangle { width: 300 height: 300 anchors.fill: parent //Кнопка Rectangle { id: button //Имя кнопки //Размещаем в центре x: parent.width / 2 - button.width / 2; y: parent.height / 2 - button.height / 2; //Размеры кнопки width: 100 height: 30 //Цвет кнопки color: "gray" //Текст кнопки Text { id: buttonLabel text: "Пуск" anchors.centerIn: parent; } //Действие мыши MouseArea { anchors.fill: parent id: mouseArea } } //Строка ввода Rectangle { id: textinputRect //Имя строки ввода //Размещаем ниже x: parent.width / 2 - button.width / 2; y: parent.height / 2 - button.height / 2+40; //Размеры строки ввода width: 100 height: 18 //цвет строки ввода color: "gray" TextInput { id: textinput objectName: "textinput" color: "#151515"; selectionColor: "blue" font.pixelSize: 12; width: parent.width-4 anchors.centerIn: parent focus: true text:"1" } } }
Обратите внимание на следующее:
- Для того, чтобы мы смогли обращаться к строке ввода из С++ у нас кроме параметра id есть еще параметр objectName, который заключается в двойные кавычки.
- Информация, которая нам потом будет нужна, содержится в параметре text.
При запуске получим следующее:
![Qt Software / [Из песочницы] QML и C++. Простой пример связки Qt Software / [Из песочницы] QML и C++. Простой пример связки](https://www.pvsm.ru/images/300f7ca24400a1fea094f15f3974ea87.png)
26. Добавим поле вывода, куда программа будет выводить ответ с именем memo.
//Поле вывода Rectangle { id: memoRect //Имя поля вывода //Размещаем ниже x: parent.width / 2 - button.width / 2; y: parent.height / 2 - button.height / 2+70; //Размеры поле вывода width: 100 height: 35 //Цвет поля вывода color: "gray" TextEdit{ id: memo objectName: "memo" wrapMode: TextEdit.Wrap width:parent.width; readOnly:true } }
В результате main.qml примет вид:
import QtQuick 1.0 Rectangle { width: 300 height: 300 anchors.fill: parent //Кнопка Rectangle { id: button //Имя кнопки //Размещаем в центре x: parent.width / 2 - button.width / 2; y: parent.height / 2 - button.height / 2; //Размеры кнопки width: 100 height: 30 //Цвет кнопки color: "gray" //Текст кнопки Text { id: buttonLabel text: "Пуск" anchors.centerIn: parent; } //Действие мыши MouseArea { anchors.fill: parent id: mouseArea } } //Строка ввода Rectangle { id: textinputRect //Имя строки ввода //Размещаем ниже x: parent.width / 2 - button.width / 2; y: parent.height / 2 - button.height / 2+40; //Размеры строки ввода width: 100 height: 18 //цвет строки ввода color: "gray" TextInput { id: textinput objectName: "textinput" color: "#151515"; selectionColor: "blue" font.pixelSize: 12; width: parent.width-4 anchors.centerIn: parent focus: true text:"1" } } //Поле вывода Rectangle { id: memoRect //Имя поля вывода //Размещаем ниже x: parent.width / 2 - button.width / 2; y: parent.height / 2 - button.height / 2+70; //Размеры поле вывода width: 100 height: 35 //Цвет поля вывода color: "gray" TextEdit{ id: memo objectName: "memo" wrapMode: TextEdit.Wrap width:parent.width; readOnly:true } } }
При запуске получим следующее:
![Qt Software / [Из песочницы] QML и C++. Простой пример связки Qt Software / [Из песочницы] QML и C++. Простой пример связки](https://www.pvsm.ru/images/c70bf631ed1d802612844dbfb17656a3.png)
Итак, мы описали интерфейс нашей программы.
C++ часть
27. При нажатии на кнопку пока ничего не происходит. Исправим это. Для начала установим взаимосвязь между QML моделью и C++ кодом. Для этого отредактируем файл mainwindow.cpp, а именно функцию MainWindow, добавив строчки:
//Находим корневой элемент Root = ui->rootObject(); //Соединяем C++ и QML, делая видимым функции С++ через элемент window ui->rootContext()->setContextProperty("window", this);
Получим следующее:
#include "mainwindow.h" MainWindow::MainWindow(QWidget *parent) : QMainWindow(parent) { //Включаем наш QML ui = new QDeclarativeView; ui->setSource(QUrl("qrc:/main.qml")); setCentralWidget(ui); ui->setResizeMode(QDeclarativeView::SizeRootObjectToView); //Находим корневой элемент Root = ui->rootObject(); //Соединяем C++ и QML, делая видимым функции С++ через элемент window ui->rootContext()->setContextProperty("window", this); } MainWindow::~MainWindow() { //Удаляем QML delete ui; }
28. В добавленном коде у нас присутствует необъявленная переменная Root . Через нее мы потом будем производить поиск всех других дочерних элементов. Объявим ее в mainwindow.h в классе в разделе private:
QObject *Root;//корневой элемент QML модели
В результате получим:
#ifndef MAINWINDOW_H #define MAINWINDOW_H #include <QMainWindow> #include <QtDeclarative/QDeclarativeView> #include <QGraphicsObject> #include <QtGui> #include <QDeclarativeContext> namespace Ui { class MainWindow; } class MainWindow : public QMainWindow { Q_OBJECT public: explicit MainWindow(QWidget *parent = 0); ~MainWindow(); private: QDeclarativeView *ui; QObject *Root;//корневой элемент QML модели }; #endif // MAINWINDOW_H
29. Пусть у нас кнопка из QML будет вызывать С++ функцию под произвольным именем FunctionC. Объявим ее в mainwindow.h в классе в разделе public:
Q_INVOKABLE void FunctionC();//Функция C++ вызываемая из QML
В результате получим:
#ifndef MAINWINDOW_H #define MAINWINDOW_H #include <QMainWindow> #include <QtDeclarative/QDeclarativeView> #include <QGraphicsObject> #include <QtGui> #include <QDeclarativeContext> namespace Ui { class MainWindow; } class MainWindow : public QMainWindow { Q_OBJECT public: explicit MainWindow(QWidget *parent = 0); ~MainWindow(); Q_INVOKABLE void FunctionC();//Функция C++ вызываемая из QML private: QDeclarativeView *ui; QObject *Root;//корневой элемент QML модели }; #endif // MAINWINDOW_H
Обратите внимание на ключевое слово Q_INVOKABLE. Именно она делает видимой функцию для QML.
30. Теперь опишем нашу функцию в mainwindow.cpp:
void MainWindow::FunctionC() { //Найдем строку ввода QObject* textinput = Root->findChild<QObject*>("textinput"); //Найдем поле вывода QObject* memo = Root->findChild<QObject*>("memo"); QString str;//Создадим новую строковую переменную //Считаем информацию со строки ввода через свойство text str=(textinput->property("text")).toString(); int a; a=str.toInt();//Переведем строку в число a++;//Добавим к числу 1 QString str2;//Создадим еще одну строковую переменную str2=QString::number(a);//Переведем число в строку //Ну и наконец выведем в поле вывода нашу информацию memo->setProperty("text", str+"+1="+str2); }
31. Ну и наконец добавим нашу функцию в обработчике нашей кнопки QML в файле main.qml. Обработчик действий мыши сейчас выглядит так:
//Действие мыши MouseArea { anchors.fill: parent id: mouseArea }
Теперь же он станет таким:
//Действие мыши MouseArea { anchors.fill: parent id: mouseArea //При нажатии вызвать фугкцию window.FunctionC() onClicked: window.FunctionC() }
В итоге получим:
import QtQuick 1.0 Rectangle { width: 300 height: 300 anchors.fill: parent //Кнопка Rectangle { id: button //Имя кнопки //Размещаем в центре x: parent.width / 2 - button.width / 2; y: parent.height / 2 - button.height / 2; //Размеры кнопки width: 100 height: 30 //Цвет кнопки color: "gray" //Текст кнопки Text { id: buttonLabel text: "Пуск" anchors.centerIn: parent; } //Действие мыши MouseArea { anchors.fill: parent id: mouseArea //При нажатии вызвать фугкцию window.FunctionC() onClicked: window.FunctionC() } } //Строка ввода Rectangle { id: textinputRect //Имя строки ввода //Размещаем ниже x: parent.width / 2 - button.width / 2; y: parent.height / 2 - button.height / 2+40; //Размеры строки ввода width: 100 height: 18 //цвет строки ввода color: "gray" TextInput { id: textinput objectName: "textinput" color: "#151515"; selectionColor: "blue" font.pixelSize: 12; width: parent.width-4 anchors.centerIn: parent focus: true text:"1" } } //Поле вывода Rectangle { id: memoRect //Имя поля вывода //Размещаем ниже x: parent.width / 2 - button.width / 2; y: parent.height / 2 - button.height / 2+70; //Размеры поле вывода width: 100 height: 35 //Цвет поля вывода color: "gray" TextEdit{ id: memo objectName: "memo" wrapMode: TextEdit.Wrap width:parent.width; readOnly:true } } }
Обратите внимание на то, что функцию вызываем через window.
Вот и всё! Теперь запускаем программу и нажимаем на кнопку. Если Вы всё сделали правильно и я не допустил ошибок, то Вы увидете:
![Qt Software / [Из песочницы] QML и C++. Простой пример связки null](https://www.pvsm.ru/images/f80987aea296831bed329d98d5b61a81.png)
Ссылка на исходники: Скачать.
Ссылка на исполняемый файл: Скачать.
Автор: Harrix
