Harrix Блог

  • Списки статей
    • Все статьи
    • IT
    • Qt
    • C++
    • Сложение двух чисел
    • Web программированиe
    • FAQ
    • Latex
    • Установка программ
    • Мифы
    • Видео
    • Про фото
  • Проекты
  • Harrix.org
  • RSS
  • Контакты

Сложение двух чисел в Qt 5.5.0 на C++ (Qt Quick)

В статье описывается создание приложения QML через Qt Quick 2.4 с выполнением кода на С++.

11.07.2015 6 комментариев 14 570 просмотров

В статье описывается создание приложения QML через Qt Quick 2.4 с выполнением кода на С++.

Более новая статья тут.

В качестве среды для разработки используется Qt 5.5.0 for Windows 32-bit.

Исходники

В статье http://blog.harrix.org/?p=3175 приведена сокращенная версия данной статьи.

В статье http://blog.harrix.org/?p=3183 рассказывается о подобном приложении, но с использованием компонентов QtQuick Controls.

Статья из цикла «Сложение двух чисел». Для меня минимальное освоение любой системы программирования начинается с возможности создания такой программы. Если можно написать приложение, в которой пользователь может ввести два числа, считать их, провести с ними какие-то действия, а потом вывести результат, то, значит, базовое владение имеется. И много задач именно из области программирования, алгоритмики можно будет решать, зная, как в конкретной системе программирования запрограммировать такую программу.

Содержание

  • Подготовка
  • Построение интерфейса
  • C++ часть

Подготовка

Создадим Qt Quick приложение.

2015-05-18_124823

2015-05-18_124838

2015-05-18_124908

Выбираем приложение на чистом qml без виджетов.

2015-05-18_124930

2015-05-18_125018

2015-05-18_125031

2015-05-18_125059

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

Если раньше при создании приложения по умолчанию создавался один qml файл, а именно main.qml, то теперь в main.qml предполагается наличие элемента Window и обработку событий, а внешний вид прописывается в файле MainForm.ui.qml (что-то типа фрагмента для тех кто знаком с Android программированием).

Почистим наши файлы main.qml и MainForm.ui.qml. В данный момент main.qml выглядит вот так:

1
2
3
4
5
6
7
8
9
10
11
12
13
import QtQuick 2.4
import QtQuick.Window 2.2
 
Window {
    visible: true
    MainForm {
        anchors.fill: parent
        mouseArea.onClicked: {
            Qt.quit();
        }
 
    }
}

2015-07-10_191436

Удалим обработчик mouseArea.onClicked. Он тут демонстрационный и закрывает приложение при клике в любой области окна приложения. Получим вот такой код файла:

1
2
3
4
5
6
7
8
9
10
import QtQuick 2.4
import QtQuick.Window 2.2
 
Window {
    visible: true
    MainForm {
        anchors.fill: parent
 
    }
}

Займемся файлом MainForm.ui.qml. Он пока содержит подобный код:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
import QtQuick 2.4
 
Rectangle {
    property alias mouseArea: mouseArea
 
    width: 360
    height: 360
 
    MouseArea {
        id: mouseArea
        anchors.fill: parent
    }
 
    Text {
        anchors.centerIn: parent
        text: "Hello World"
    }
}

Удалим свойство mouseArea, компоненты MouseArea и Text.

1
2
3
4
5
6
7
8
import QtQuick 2.4
 
Rectangle {
 
    width: 360
    height: 360
 
}

Добавим в основной Rectangle следующую конструкцию:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
    Column {
        spacing: 5
        anchors.centerIn: parent;
 
        //Кнопка
        Rectangle {
            id: button //Имя кнопки
 
            //Размеры кнопки
            width: 100
            height: 30
 
            //Цвет кнопки
            color: "#0066ff"
 
            //Текст кнопки
            Text {
                id: buttonLabel
                text: "Сложить"
                color: "#ffffff";
                anchors.centerIn: parent;
            }
 
            //Действие мыши
            MouseArea {
                id: mouseArea1
                anchors.fill: parent
                hoverEnabled: true;
            }
        }
 
        //Строка ввода первого числа
        Rectangle {
            id: textinputRect1 //Имя строки ввода
 
            //Размеры строки ввода
            width: 100
            height: 18
 
            //цвет строки ввода
            color: "#ffffff"
 
            TextInput {
                id: textinput1
                objectName: "textinput1"
                color: "#0066ff";
                selectionColor: "blue"
                font.pixelSize: 12;
                width: parent.width-4
                anchors.centerIn: parent
                focus: true
                text:"1"
            }
        }
 
        //Строка ввода второго числа
        Rectangle {
            id: textinputRect2 //Имя строки ввода
 
            //Размеры строки ввода
            width: 100
            height: 18
 
            //цвет строки ввода
            color: "#ffffff"
 
            TextInput {
                id: textinput2
                objectName: "textinput2"
                color: "#0066ff";
                selectionColor: "blue"
                font.pixelSize: 12;
                width: parent.width-4
                anchors.centerIn: parent
                focus: true
                text:"1"
            }
        }
 
        //Поле вывода
        Rectangle {
            id: memoRect //Имя поля вывода
 
            //Размеры поле вывода
            width: 100
            height: 35
 
            //Цвет поля вывода
            color: "#ffffff"
 
            TextEdit{
                id: memo
                color: "#0066ff"
                objectName: "memo"
                wrapMode: TextEdit.Wrap
                width:parent.width;
                readOnly:true
            }
        }
    }

Получим такой код файла MainForm.ui.qml (я в корневой Rectangle добавил еще фоновый цвет):

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
import QtQuick 2.4
 
Rectangle {
 
    width: 360
    height: 360
 
    color: "#ececec";
 
    Column {
        spacing: 5
        anchors.centerIn: parent;
 
        //Кнопка
        Rectangle {
            id: button //Имя кнопки
 
            //Размеры кнопки
            width: 100
            height: 30
 
            //Цвет кнопки
            color: "#0066ff"
 
            //Текст кнопки
            Text {
                id: buttonLabel
                text: "Сложить"
                color: "#ffffff";
                anchors.centerIn: parent;
            }
 
            //Действие мыши
            MouseArea {
                id: mouseArea1
                anchors.fill: parent
                hoverEnabled: true;
            }
        }
 
        //Строка ввода первого числа
        Rectangle {
            id: textinputRect1 //Имя строки ввода
 
            //Размеры строки ввода
            width: 100
            height: 18
 
            //цвет строки ввода
            color: "#ffffff"
 
            TextInput {
                id: textinput1
                objectName: "textinput1"
                color: "#0066ff";
                selectionColor: "blue"
                font.pixelSize: 12;
                width: parent.width-4
                anchors.centerIn: parent
                focus: true
                text:"1"
            }
        }
 
        //Строка ввода второго числа
        Rectangle {
            id: textinputRect2 //Имя строки ввода
 
            //Размеры строки ввода
            width: 100
            height: 18
 
            //цвет строки ввода
            color: "#ffffff"
 
            TextInput {
                id: textinput2
                objectName: "textinput2"
                color: "#0066ff";
                selectionColor: "blue"
                font.pixelSize: 12;
                width: parent.width-4
                anchors.centerIn: parent
                focus: true
                text:"1"
            }
        }
 
        //Поле вывода
        Rectangle {
            id: memoRect //Имя поля вывода
 
            //Размеры поле вывода
            width: 100
            height: 35
 
            //Цвет поля вывода
            color: "#ffffff"
 
            TextEdit{
                id: memo
                color: "#0066ff"
                objectName: "memo"
                wrapMode: TextEdit.Wrap
                width:parent.width;
                readOnly:true
            }
        }
    }
 
}

Обратите внимание, что для всех элементов, к которым вы потом захотите обращаться в С++, пропишите не только свойство id, но и свойство objectName со строковым значением совпадающим с id.

Кратко пробежимся по коду, который у нас получился. Все компоненты мы расположили в главном корневом Rectangle. В нем находится компонент Column, который располагает находящиеся в нем компоненты в столбик (вертикальная разметка компонентов).

1
2
3
4
5
    Column {
        spacing: 5
        anchors.centerIn: parent;
    ...
    }

Внутри него находится четыре компонента Rectangle.

Первый имеет id равное button, и это обычная кнопка, а точнее закрашенный прямоугольник с текстом внутри и областью для воздействия мышью с id равным mouseArea1.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
        //Кнопка
        Rectangle {
            id: button //Имя кнопки
 
            //Размеры кнопки
            width: 100
            height: 30
 
            //Цвет кнопки
            color: "#0066ff"
 
            //Текст кнопки
            Text {
                id: buttonLabel
                text: "Сложить"
                color: "#ffffff";
                anchors.centerIn: parent;
            }
 
            //Действие мыши
            MouseArea {
                id: mouseArea1
                anchors.fill: parent
                hoverEnabled: true;
            }
        }

Второй и третий Rectangle содержит компонент TextInput, то есть строку для ввода информации. В них будем записывать два наших числа.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
        //Строка ввода первого числа
        Rectangle {
            id: textinputRect1 //Имя строки ввода
 
            //Размеры строки ввода
            width: 100
            height: 18
 
            //цвет строки ввода
            color: "#ffffff"
 
            TextInput {
                id: textinput1
                objectName: "textinput1"
                color: "#0066ff";
                selectionColor: "blue"
                font.pixelSize: 12;
                width: parent.width-4
                anchors.centerIn: parent
                focus: true
                text:"1"
            }
        }
 
        //Строка ввода второго числа
        Rectangle {
            id: textinputRect2 //Имя строки ввода
 
            //Размеры строки ввода
            width: 100
            height: 18
 
            //цвет строки ввода
            color: "#ffffff"
 
            TextInput {
                id: textinput2
                objectName: "textinput2"
                color: "#0066ff";
                selectionColor: "blue"
                font.pixelSize: 12;
                width: parent.width-4
                anchors.centerIn: parent
                focus: true
                text:"1"
            }
        }

В последнем четвертом Rectangle содержится поле для вывода текста: TextEdit.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
        //Поле вывода
        Rectangle {
            id: memoRect //Имя поля вывода
 
            //Размеры поле вывода
            width: 100
            height: 35
 
            //Цвет поля вывода
            color: "#ffffff"
 
            TextEdit{
                id: memo
                color: "#0066ff"
                objectName: "memo"
                wrapMode: TextEdit.Wrap
                width:parent.width;
                readOnly:true
            }
        }

Если мы запустим приложение, то получим следующее:

2015-07-11_124107

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

C++ часть

При нажатии на кнопку пока ничего не происходит. Исправим это. Для начала установим взаимосвязь между QML моделью и C++ кодом. Для этого создадим класс, через которое будем осуществлять взаимодействие.

Правой кнопкой щелкнем по проекту и выбираем пункт Add New....

2015-07-11_125006

Там выбираем C++ Class.

2015-07-11_125928

Там вводим название нашего нового класса, например, myClass, также добавив подключение инклуда QObject.

2015-07-11_130030

2015-07-11_130053

В итоге получаем наш класс:

2015-07-11_130211

Начнем его редактирование. Перейдем вначале в заголовочный файл myclass.h. Сейчас он имеет такой вид:

1
2
3
4
5
6
7
8
9
10
11
12
#ifndef MYCLASS_H
#define MYCLASS_H
 
#include <QObject>
 
class myClass
{
public:
    myClass();
};
 
#endif // MYCLASS_H

Поменяем содержимое на такое:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
#ifndef MYCLASS_H
#define MYCLASS_H
 
#include <QObject>
#include <QDebug>
 
class MyClass : public QObject
{
    Q_OBJECT
public:
    MyClass(QObject *QMLObject) : viewer(QMLObject) {}
 
signals:
 
public slots:
    void buttonClicked(const QString& in);
protected:
    QObject *viewer;
};
 
#endif // MYCLASS_H

Что мы сделали?

  • Подключили модули QDebug – это лишь для отображения дебажной информации.
  • Сделали класс наследником класса QObject.
  • Добавили мета-информацию Q_OBJECT.
  • Прописали пустой конструктор класса с начальным присвоением объекта viewer.
  • Добавили объект viewer. Это корневой объект все нашей сцены, в которой будут располагаться все наши объекты из qml формы.
  • И прописали метод, обрабатывающий клик кнопки, который принимает в качестве параметра некоторую строку: void buttonClicked(const QString& in).

Перейдем в файл myclass.cpp. На данный момент он выглядит так:

1
2
3
4
5
6
#include "myclass.h"
 
myClass::myClass()
{
 
}

Конструктор, реализованный тут, нам больше не нужен, так как конструктор прописали в заголовочном файле. А вот метод buttonClicked реализовать нужно. Меняем содержимое файла на такое:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
#include "myclass.h"
 
void MyClass::buttonClicked(const QString& in)
{
    qDebug() << in;//Просто выведем информацию строки in в консоль Debug. Просто так.
 
    //Найдем строки ввода
    QObject* textinput1 = viewer->findChild<QObject*>("textinput1");
    QObject* textinput2 = viewer->findChild<QObject*>("textinput2");
    //Найдем поле вывода
    QObject* memo = viewer->findChild<QObject*>("memo");
 
    //Считаем информацию со строк ввода через свойство text
    QString str1=(textinput1->property("text")).toString();
    QString str2=(textinput2->property("text")).toString();
 
    int a = str1.toInt();//Переведем строку в число
    int b = str2.toInt();//Переведем строку в число
 
    int c = a + b; //Вычисления наши
 
    QString strResult=QString::number(c);//Переведем результат в строку
 
    //Ну и наконец выведем в поле вывода нашу информацию
    memo->setProperty("text", str1+" + "+str2+" = "+strResult);
}

Что тут у нас?

  • Элементы в QML документы мы находим через функцию findChild.
  • А изменяем через функцию setProperty.
  • viewer – это тот QObject, который использовался при создании класса.

Приложение сейчас должно запуститься, но при нажатию на кнопку ничего не произойдет.

2015-07-11_133707

Это объясняется тем, что мы не связали наш метод с QML моделью. К тому же метод клика на кнопку реализован в классе, экземпляр которого мы не создали.

Вначале пропишем вызов в QML коде. Для этого откроем файл MainForm.ui.qml. И там в объекте MouseArea пропишем строчку:

1
onClicked: _myClass.buttonClicked("Worked?")

При этом скорее всего у вас строчка будет поддчеркиваться красным, так как Qt Creator считает, что нельзя функции прописывать в файлах qml форм. Но это можно. Пример того как сделать, чтобы не поддчеркивалось, рассмотрено в примере с контролами (нужно вынести в main.qml обработчик, но пока пойдем по простому пути).

2015-07-11_141840

В качестве параметра мы передали строку “Worked?”, которую мы в методе buttonClicked первой же строчкой просто так выведем в Debug консоль.

Теперь, перейдем в файл main.cpp, чтобы прописать создание экземпляра класса и связать его с нужными объектами.

Пока данный файл имеет вид:

1
2
3
4
5
6
7
8
9
10
11
12
#include <QGuiApplication>
#include <QQmlApplicationEngine>
 
int main(int argc, char *argv[])
{
    QGuiApplication app(argc, argv);
 
    QQmlApplicationEngine engine;
    engine.load(QUrl(QStringLiteral("qrc:/main.qml")));
 
    return app.exec();
}

Добавим два заголовочных файла:

1
2
#include <QQmlContext>
#include "myclass.h"

А в функции main после загрузки qml файла пропишем строчки:

1
2
3
QObject* root = engine.rootObjects()[0];
MyClass myClass(root);
engine.rootContext()->setContextProperty("_myClass", &myClass);

В первой строчке мы находим корневой объект в QML модели. Во второй строчке создаем экземпляр нашего класса. И в третьей строчке связываем наш класс и qml модель.

Теперь main.cpp выглядит вот так:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
#include <QGuiApplication>
#include <QQmlApplicationEngine>
 
#include <QQmlContext>
#include "myclass.h"
 
int main(int argc, char *argv[])
{
    QGuiApplication app(argc, argv);
 
    QQmlApplicationEngine engine;
    engine.load(QUrl(QStringLiteral("qrc:/main.qml")));
 
    QObject* root = engine.rootObjects()[0];
    MyClass myClass(root);
    engine.rootContext()->setContextProperty("_myClass", &myClass);
 
    return app.exec();
}

Если всё сделали правильно, то при запуск приложения и нажатия на кнопку получим следующее:

2015-07-11_141139

Вот и всё)


Статьи по теме:

  1. Сложение двух чисел в Qt 5.5.0 на C++ (Qt Quick Controls)
  2. Сложение двух чисел в Qt 5.6.0 на C++ (Qt Quick)
  3. Сложение двух чисел в Qt 5.6.0 на C++ (Qt Labs Controls)
  4. Сложение двух чисел в Qt 5.7.0 на C++ (Qt Quick Controls 2)

IT C++, Qt, QtQuick, Программа сложения двух чисел

© 2014 Harrix