Qt Software / [Из песочницы] QML и C++. Простой пример связки

в 1:53, , рубрики: c++, QML, для чайников, метки: , ,

image
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
image

Создание QML приложения

1. Создаем GUI Приложение: Файл -> Новый файл или проект.... Там слева выбираем Проект Qt Widget, с справа GUI приложение Qt. Потом жмем внизу кнопку "Выбрать...".
Qt Software / [Из песочницы] QML и C++. Простой пример связки

2. В следующем окне выбираем название нашего проекта (без пробелов и русских букв). Например, в нашем случае это "Example".
Qt Software / [Из песочницы] QML и C++. Простой пример связки

3. В следующем окне у Вас должна стоять галочка у "Desktop". Если ее у Вас ее нет, то Вы неверно установили Qt Creator (или Вы намерено не хотите создавать десктопные приложения). Та сборка Qt Creator официальная, которую я ставил (2.3), по умолчанию почему-то десктопные части не устанавливала.
Qt Software / [Из песочницы] QML и C++. Простой пример связки

4. В следующем окне снимите галочку с пункта "Создать форму".
Qt Software / [Из песочницы] QML и C++. Простой пример связки

5. В следующем окне можно ничего не менять. И жмем кнопку "Завершить".
Qt Software / [Из песочницы] QML и C++. Простой пример связки

Редактирование файла проекта

6. Отредактируем файл проекта (у нас это Example.pro):
Qt Software / [Из песочницы] QML и C++. Простой пример связки

И добавим к строчке "QT += core gui" слово "declarative". В итоге получим строчку:

QT       += core gui declarative
Создание QML проекта

7. По папке с проектом в Qt Creator щелкаем правой кнопкой и идем к пункту "Добавить новый..."
Qt Software / [Из песочницы] QML и C++. Простой пример связки

8. Выбираем слева "QML", а справа "Файл QML".
Qt Software / [Из песочницы] QML и C++. Простой пример связки

9. Назовем его "main".
Qt Software / [Из песочницы] QML и C++. Простой пример связки

10. Следующее окно без изменений.
Qt Software / [Из песочницы] QML и C++. Простой пример связки

11. В результате получим файл "main.qml" с текстом:

import QtQuick 1.0  Rectangle {     width: 100     height: 62 }
Создаем файл ресурсов

12. По папке с проектом в Qt Creator щелкаем правой кнопкой и идем к пункту "Добавить новый..."

Qt Software / [Из песочницы] QML и C++. Простой пример связки

13. Выбираем слева "Qt", а справа "Файл ресурсов Qt".
Qt Software / [Из песочницы] QML и C++. Простой пример связки

14. Назовем его "res".
Qt Software / [Из песочницы] QML и C++. Простой пример связки

15. Следующее окно без изменений.
Qt Software / [Из песочницы] QML и C++. Простой пример связки

В результате получим файд "res.qrc"

16. Добавим префикс. Для этого щелкнем по кнопке "Добавить", а там щелкнуть "Добавить префикс".
Qt Software / [Из песочницы] QML и C++. Простой пример связки

17. Измените текст префикса на "/".
Qt Software / [Из песочницы] QML и C++. Простой пример связки

18. Добавим наш QML файл. Для этого щелкнем по кнопке "Добавить", а там щелкнуть "Добавить файлы".
Qt Software / [Из песочницы] QML и C++. Простой пример связки

19. И выберем наш файл "main.qml". И файл добавится к ресурсам нашего приложения:
Qt Software / [Из песочницы] QML и C++. Простой пример связки

Если сейчас запустим наше приложение, то qml пока не увидим:
Qt Software / [Из песочницы] QML и C++. Простой пример связки

Редактирование исходников

Теперь займемся подключением 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++. Простой пример связки

Написание приложения

Теперь мы можем перейти к написанию непосредственно приложения, которое будет решать нашу задачу.

Построение интерфейса.

23. На данный момент main.qml выглядит так:

import QtQuick 1.0  Rectangle {     width: 100     height: 62 }

Qt Software / [Из песочницы] QML и C++. Простой пример связки

Отредактируем его, изменив главный прямоугольник-окно:

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++. Простой пример связки

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++. Простой пример связки

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++. Простой пример связки

Итак, мы описали интерфейс нашей программы.

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.

Вот и всё! Теперь запускаем программу и нажимаем на кнопку. Если Вы всё сделали правильно и я не допустил ошибок, то Вы увидете:

null

Ссылка на исходники: Скачать.
Ссылка на исполняемый файл: Скачать.

Автор: Harrix


* - обязательные к заполнению поля


https://ajax.googleapis.com/ajax/libs/jquery/3.4.1/jquery.min.js