Добрый день, %username%!
Некоторое время назад делал знакомому лабораторную, тематика которой – код Хэмминга. Программа представляла собой обыкновенное Qt приложение с минимальным набором контролов. Сдача прошла успешно, прошло некоторое время, и его теперь другу необходимо тоже сдать лабораторную на эту же тематику. Ту же программу, очевидно, сдавать нельзя. Тут возникает вопрос – как сделать программу с тремя кнопками и двумя текстбоксами непохожей на предыдущую? Мне в голову пришла мысль переписать интерфейс с помощью Qt Quick, а логику и расчеты программы оставить в С++, а заодно и рассказать интересующимся людям, как я обычно делаю подобные вещи. По Qt Quick не так много литературы, тем более на русском, так что очень надеюсь, что данная статья будет полезна и интересна. Уточню – основное внимание уделено способам взаимодействия Qt Quick и C++, в меньшей мере основам Qt и QML, но никак не подсчету кодов Хэмминга.
Итак, идут последние секунды установки Qt Sdk у меня на работе, мы начинаем.
Открываем QtCreator, создаем новый проект типа «GUI приложение Qt». Выбираем директорию, название, затем вот в это окошке мастера:
убираем галку «Создать форму». Она нам не понадобится, весь интерфейс будем писать ручками.
В сгенерированном файле mainwindow.h включите следующие заголовочные файлы:
#include #include <QtDeclarative/QDeclarativeContext>
#include <QtDeclarative/QDeclarativeView>
В конструкторе класса MainWindow внесем следующие изменения:
Немного поясню – мы создаем виджет типа QDeclarativeView – это элемент, способный отображать QML. Затем задаем имя корневого QML элемента — main.qml, который берется из ресурсов, которые добавим позже. Затем получаем контекст виджета, чтобы добавить в нем новое свойство «window”. Теперь из QML можно будет обращаться к объекту под названием window — это есть наша форма. Зачем это нужно станет ясно чуть позже. Ниже задается режим изменения размера – теперь корневой QML элемент будет изменять размер в соответствии с окном, а не наоборот. Метод setCentralWidget устанавливает для QMainWindow центральный виджет. Все, кто сталкивался с Qt, несомненно знакомы с ним.
Наш проект нуждается в QML файле, котором говорилось выше. Добавим его:
Теперь похожим образом добавляем файл ресурсов:
Он автоматически открывается, внизу жнем «Добавить» -> «Добавить префикс», появляется "/new/prefix1". Стираем и оставляем только «/» для простоты. Теперь добавляем туда файл main.qml ( “Добавить” -> «Добавить файл» ). Еще одна маленькая вещь – в файл *.pro нужно внести одно изменение
QT += core declarative
Таким нехитрым образом мы выставляем проекту зависимость от библиотеки QtDeclarative4
Теперь можно смело запускать проект и видеть … Белый квадрат 100 на 62 :) Но внешность обманчива – на самом деле это куда больше, чем белый квадрат, это приложение, интерфейс которого написан на QML, а логика на C++.
Примерно так начинается создание любого приложения, которое будет гибридом Qt Quick и C++. Основной момент — получение корневого контекста виджета QDeclarativeView, добавление нового свойства для доступа к объекту C++. Это свойство станет своего рода мостом между QML и С++.
Итак, этап создания базиса пройден, теперь логика работы.
В файле mainwindow.h в описание класса добавляем
По названию ясно, что первые два слота будут заниматься кодированием и декодированием. Принимать на вход оба будут строку, которую пользователь введет в QML, а возвращать, соответственно, кодированный или декодированный вариант. Почему слоты вместо обыкновенных функций? Потому что именно слоты, а так же функции, объявленные с помощью макроса Q_INVOKABLE (подробнее см. документацию ) могут быть вызваны из QML посредством обращения к объекту, сделанному видимым с помощью setContextProperty(). Проще говоря, можно будет написать window.slotEncode() в QML :) Так же из QML кода доступны все свойства, объявленные с помощью макроса Q_PROPERTY — к ним можно обращаться прям по имени.
Реализацию данных слотов я возьму из старого проекта, и не приведу их тут в полном виде, можете скачать архив по ссылке ниже. Есть так же небольшая оговорка – в процессе кодирования и декодирования строится таблица, которую мне совсем не хотелось переписывать, поэтому она останется в первоначальном виде и просто будет показана в отдельном окне. Так же был добавлен слот slotCheck(int v) для служебных целей, использующийся только в процессе подсчета кода, и конечно, его нужно добавить, однако совсем не стоит задумываться, для чего он – ибо не относится к уроку!
Теперь осталось только сделать интерфейс программы :)
Пожалуй, я выдам ту версию интерфейса, которая делается минут за 15, обыкновенным программистом без творческого взгляда на мир (хотя обычно мне помогает моя девушка-художник делать делать подобные вещи):
Совсем не уверен, подсветится ли синтаксис верно — будем надеяться, что схожесть с JavaScript сыграет свою положительную роль!
Ссылка на исходники — Тык!
Результат работы:
Результатом нашей работы стало гибридное приложение. В перспективе создание подобных приложений позволяет совместить нестандартный интерфейс QtQuick с высокопроизводительным С++ кодом. Надеюсь, статья будет полезной интересующимся данными технологиями, ибо вопросы «Дайте литературу по Qt Quick» встречаются все чаще. Спасибо за внимание!
Небольшая предыстория:
Некоторое время назад делал знакомому лабораторную, тематика которой – код Хэмминга. Программа представляла собой обыкновенное Qt приложение с минимальным набором контролов. Сдача прошла успешно, прошло некоторое время, и его теперь другу необходимо тоже сдать лабораторную на эту же тематику. Ту же программу, очевидно, сдавать нельзя. Тут возникает вопрос – как сделать программу с тремя кнопками и двумя текстбоксами непохожей на предыдущую? Мне в голову пришла мысль переписать интерфейс с помощью Qt Quick, а логику и расчеты программы оставить в С++, а заодно и рассказать интересующимся людям, как я обычно делаю подобные вещи. По Qt Quick не так много литературы, тем более на русском, так что очень надеюсь, что данная статья будет полезна и интересна. Уточню – основное внимание уделено способам взаимодействия Qt Quick и C++, в меньшей мере основам Qt и QML, но никак не подсчету кодов Хэмминга.
Создание каркаса
Итак, идут последние секунды установки Qt Sdk у меня на работе, мы начинаем.
Открываем QtCreator, создаем новый проект типа «GUI приложение Qt». Выбираем директорию, название, затем вот в это окошке мастера:
убираем галку «Создать форму». Она нам не понадобится, весь интерфейс будем писать ручками.
В сгенерированном файле mainwindow.h включите следующие заголовочные файлы:
#include #include <QtDeclarative/QDeclarativeContext>
#include <QtDeclarative/QDeclarativeView>
В конструкторе класса MainWindow внесем следующие изменения:
MainWindow::MainWindow(QWidget *parent)
: QMainWindow(parent)
{
QDeclarativeView* dv = new QDeclarativeView();
dv->setSource(QUrl("qrc:/main.qml"));
QDeclarativeContext* cntx = dv->rootContext();
cntx->setContextProperty("window",this);
dv->setResizeMode(QDeclarativeView::SizeRootObjectToView);
setCentralWidget(dv);
}
Немного поясню – мы создаем виджет типа QDeclarativeView – это элемент, способный отображать QML. Затем задаем имя корневого QML элемента — main.qml, который берется из ресурсов, которые добавим позже. Затем получаем контекст виджета, чтобы добавить в нем новое свойство «window”. Теперь из QML можно будет обращаться к объекту под названием window — это есть наша форма. Зачем это нужно станет ясно чуть позже. Ниже задается режим изменения размера – теперь корневой QML элемент будет изменять размер в соответствии с окном, а не наоборот. Метод setCentralWidget устанавливает для QMainWindow центральный виджет. Все, кто сталкивался с Qt, несомненно знакомы с ним.
Наш проект нуждается в QML файле, котором говорилось выше. Добавим его:
Теперь похожим образом добавляем файл ресурсов:
Он автоматически открывается, внизу жнем «Добавить» -> «Добавить префикс», появляется "/new/prefix1". Стираем и оставляем только «/» для простоты. Теперь добавляем туда файл main.qml ( “Добавить” -> «Добавить файл» ). Еще одна маленькая вещь – в файл *.pro нужно внести одно изменение
QT += core declarative
Таким нехитрым образом мы выставляем проекту зависимость от библиотеки QtDeclarative4
Теперь можно смело запускать проект и видеть … Белый квадрат 100 на 62 :) Но внешность обманчива – на самом деле это куда больше, чем белый квадрат, это приложение, интерфейс которого написан на QML, а логика на C++.
Примерно так начинается создание любого приложения, которое будет гибридом Qt Quick и C++. Основной момент — получение корневого контекста виджета QDeclarativeView, добавление нового свойства для доступа к объекту C++. Это свойство станет своего рода мостом между QML и С++.
Создание интерфейса и логики
Итак, этап создания базиса пройден, теперь логика работы.
В файле mainwindow.h в описание класса добавляем
public slots:
QString slotEncode(QString sIn);
QString slotDecode(QString sIn);
bool slotCheck(int val);
По названию ясно, что первые два слота будут заниматься кодированием и декодированием. Принимать на вход оба будут строку, которую пользователь введет в QML, а возвращать, соответственно, кодированный или декодированный вариант. Почему слоты вместо обыкновенных функций? Потому что именно слоты, а так же функции, объявленные с помощью макроса Q_INVOKABLE (подробнее см. документацию ) могут быть вызваны из QML посредством обращения к объекту, сделанному видимым с помощью setContextProperty(). Проще говоря, можно будет написать window.slotEncode() в QML :) Так же из QML кода доступны все свойства, объявленные с помощью макроса Q_PROPERTY — к ним можно обращаться прям по имени.
Реализацию данных слотов я возьму из старого проекта, и не приведу их тут в полном виде, можете скачать архив по ссылке ниже. Есть так же небольшая оговорка – в процессе кодирования и декодирования строится таблица, которую мне совсем не хотелось переписывать, поэтому она останется в первоначальном виде и просто будет показана в отдельном окне. Так же был добавлен слот slotCheck(int v) для служебных целей, использующийся только в процессе подсчета кода, и конечно, его нужно добавить, однако совсем не стоит задумываться, для чего он – ибо не относится к уроку!
Теперь осталось только сделать интерфейс программы :)
Пожалуй, я выдам ту версию интерфейса, которая делается минут за 15, обыкновенным программистом без творческого взгляда на мир (хотя обычно мне помогает моя девушка-художник делать делать подобные вещи):
import QtQuick 1.0
Rectangle {
width: 365
height: 200
gradient: Gradient {
GradientStop {
position: 0
color: "#696363"
}
GradientStop {
position: 1
color: "#000000"
}
}
Text {
id: text1
x: 37
y: 27
color: "#fbfbfb"
text: "Исходное слово"
style: Text.Raised
font.pixelSize: 12
}
Text {
id: text2
x: 198
y: 27
color: "#ffffff"
text: "Код Хэмминга"
style: Text.Raised
font.pixelSize: 12
}
// Поле ввода прямого кода.
Rectangle {
color: "#4de013"
radius: 6
border.width: 5
border.color: "#f5f9f4"
x: 36
y: 66
width: 133
height: 20
TextInput {
id: text_input1
width: parent.width - 20
height: parent.height - 5
anchors.horizontalCenter: parent.horizontalCenter
anchors.verticalCenter: parent.verticalCenter
text: ""
font.pixelSize: 12
}
}
// Поле для кода Хэмминга.
Rectangle {
color: "#48c819"
radius: 6
border.width: 5
border.color: "#f5f9f4"
width: 133
height: 20
x: 201
y: 66
TextInput {
id: text_input2
width: parent.width - 20
height: parent.height - 5
anchors.horizontalCenter: parent.horizontalCenter
anchors.verticalCenter: parent.verticalCenter
text: ""
font.pixelSize: 12
}
}
// Кнопки кодирования.
Rectangle {
id: bEncode
property alias text: label.text
width: 135
height: 60
radius: 20
border.width: 2
border.color: "#090606"
gradient: Gradient {
GradientStop {
id: gradientstop1
position: 0.01
color: "#ffffff"
}
GradientStop {
id: gradientstop2
position: 0.28
color: "#867d7d"
}
GradientStop {
id: gradientstop3
position: 1
color: "#000000"
}
}
signal clicked()
x: 36
y: 110
Text {
id: label
color: "#ffffff"
text: "Кодировать"
font.strikeout: false
font.pointSize: 10
horizontalAlignment: Text.AlignHCenter
anchors.centerIn: parent
}
MouseArea {
id: mouseArea
anchors.fill: parent
hoverEnabled: true
onClicked: {
text_input2.text = window.slotEncode(text_input1.text)
}
onEntered: {
bEncode.state = "green"
}
onExited: {
bEncode.state = "gray"
}
}
states: [
State {
name: "gray"
},
State {
name: "green"
PropertyChanges {
target: gradientstop1
color: "#ffffff"
}
PropertyChanges {
target: gradientstop2
color: "#34c22a"
}
PropertyChanges {
target: gradientstop3
color: "#000000"
}
}
]
}
// Кнопка декодирования.
Rectangle {
id: bDecode
property alias text: label.text
width: 136
height: 60
radius: 20
border.width: 2
border.color: "#090606"
gradient: Gradient {
GradientStop {
id: gradientstop21
position: 0.01
color: "#ffffff"
}
GradientStop {
id: gradientstop22
position: 0.28
color: "#867d7d"
}
GradientStop {
id: gradientstop23
position: 1
color: "#000000"
}
}
signal clicked()
x: 200
y: 110
Text {
id: label2
text: "Декодировать"
color: "#ffffff"
font.strikeout: false
font.pointSize: 10
horizontalAlignment: Text.AlignHCenter
anchors.centerIn: parent
}
MouseArea {
id: mouseArea2
anchors.fill: parent
hoverEnabled: true
onClicked: {
text_input1.text = window.slotDecode(text_input2.text)
}
onEntered: {
bDecode.state = "green"
}
onExited: {
bDecode.state = "gray"
}
}
states: [
State {
name: "gray"
},
State {
name: "green"
PropertyChanges {
target: gradientstop21
color: "#ffffff"
}
PropertyChanges {
target: gradientstop22
color: "#34c22a"
}
PropertyChanges {
target: gradientstop23
color: "#000000"
}
}
]
}
}
Совсем не уверен, подсветится ли синтаксис верно — будем надеяться, что схожесть с JavaScript сыграет свою положительную роль!
Ссылка на исходники — Тык!
Результат работы:
Небольшой итог
Результатом нашей работы стало гибридное приложение. В перспективе создание подобных приложений позволяет совместить нестандартный интерфейс QtQuick с высокопроизводительным С++ кодом. Надеюсь, статья будет полезной интересующимся данными технологиями, ибо вопросы «Дайте литературу по Qt Quick» встречаются все чаще. Спасибо за внимание!