⬆️ ⬇️

Creating hybrid Qt Quick and C ++ applications

Good afternoon,% username%!





A little background:




Some time ago, I did a laboratory friend, whose subject is the Hamming code. The program was an ordinary Qt application with a minimum set of controls. The delivery was successful, some time has passed, and now his friend also needs to pass a laboratory on the same subject. The same program, obviously, can not be passed. Then the question arises - how to make a program with three buttons and two text boxes unlike the previous one? I had the idea to rewrite the interface using Qt Quick, and leave the logic and calculations of the program in C ++, and at the same time tell interested people how I usually do things like that. According to Qt Quick, there is not so much literature, especially in Russian, so I really hope that this article will be useful and interesting. To clarify, the focus is on how Qt Quick interacts with C ++, to a lesser extent, the basics of Qt and QML, but not the counting of Hamming codes.

')

Creation of the frame




So, the last seconds of installing Qt Sdk in my work, we are starting.

Open QtCreator, create a new project like “Qt GUI application”. Select a directory, name, then in this window of the wizard:

image

remove the checkbox "Create form". We do not need it, we will write the entire interface with pens.

In the generated mainwindow.h file, include the following header files:



#include #include <QtDeclarative / QDeclarativeContext>

#include <QtDeclarative / QDeclarativeView>



In the constructor of the class MainWindow make the following changes:



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);

}




I will explain a little bit - we create a widget of the type QDeclarativeView - this is an element capable of displaying QML. Then we set the name of the root QML element - main.qml, which is taken from the resources that we add later. Then we get the context of the widget to add a new property “window” in it. Now from QML it will be possible to access the object called window - this is our form. Why this is needed will become clear a little later. The resizing mode is set below - now the root QML element will resize according to the window, and not vice versa. The setCentralWidget method sets a central widget for QMainWindow. Anyone who has experienced Qt is undoubtedly familiar with it.



Our project needs a QML file, as mentioned above. Add it:

image

Now add the resource file in a similar way:

image



It opens automatically, click “Add” -> “Add prefix” below, “/ new / prefix1” appears. We erase and leave only “/” for simplicity. Now add the main.qml file (“Add” -> “Add file”). Another little thing - you need to make one change to the * .pro file

QT + = core declarative

In this simple way, we expose the project to a dependency on the QtDeclarative4 library.



Now you can safely run the project and see ... White square 100 to 62 :) But appearance is deceptive - in fact it is much more than a white square, this application, whose interface is written in QML, and the logic in C ++.

Something like this begins the creation of any application that will be a hybrid of Qt Quick and C ++. The main point is getting the root context of the QDeclarativeView widget, adding a new property to access the C ++ object. This property will become a kind of bridge between QML and C ++.



Creation of interface and logic


So, the creation of the base is passed, now the logic of the work.

In the mainwindow.h file we add to the class description

public slots:

QString slotEncode(QString sIn);

QString slotDecode(QString sIn);

bool slotCheck(int val);



By name it is clear that the first two slots will be engaged in coding and decoding. Both will accept the input string that the user enters in QML, and return, respectively, the encoded or decoded version. Why slots instead of ordinary functions? Because it is slots, as well as functions, declared using the Q_INVOKABLE macro (see the documentation for details) can be called from QML by referring to an object made visible using setContextProperty (). Simply put, it will be possible to write window.slotEncode () in QML :) Also, all the properties declared using the Q_PROPERTY macro are available from the QML code - they can be accessed directly by name.



I will take the implementation of these slots from the old project, and will not give them here in full, you can download the archive from the link below. There is also a small reservation - in the process of encoding and decoding a table is built, which I didn’t want to rewrite at all, so it will remain in its original form and will simply be shown in a separate window. A slotCheck (int v) slot was also added for service purposes, used only in the process of counting the code, and of course, you need to add it, but you shouldn’t think at all what it is for - because it doesn’t belong to the lesson!



Now it remains only to make the program interface :)

Perhaps, I will give out that version of the interface, which is done in 15 minutes, by an ordinary programmer without a creative view of the world (although usually my girl artist helps me to do such things):

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"

}

}

]



}

}







I'm not at all sure if the syntax will be highlighted correctly - let's hope that the similarity with JavaScript will play its positive role!



Link to the source - Tyk!



Result of work:

image



Small total




The result of our work was a hybrid application. In the future, the creation of such applications allows you to combine non-standard QtQuick interface with high-performance C ++ code. I hope the article will be useful to those interested in these technologies, because the questions "Give Qt Quick literature" are becoming more common. Thanks for attention!

Source: https://habr.com/ru/post/122046/



All Articles