What will this cover: How to do a simple Qt application using QML (from QtQuick component)
Why: Qt uses C++, but if you work with QML you can do all the logic in Javascript, so for those that don't want to learn C++, this might be a easy way to make a simple game and yet have the possibility to work with C++ or C++ libraries if wanted. Oh yeah, you can use Qt on Windows, Linux or Mac OS X.
Prerequisites: Qt 4.8 is a nice start, don't download the online installer, it's shit, download the Qt Library and Qt Creator (IDE) and you have everything you will ever need.
http://releases.qt-project.org/qt4/source/qt-win-opensource-4.8.2-mingw.exe
http://get.qt.nokia.com/qtcreator/qt-creator-win-opensource-2.5.0.exe
This version uses MinGW, there are versions for you to work with Visual Studio, but I've never tried.
About QML: Although QML looks simple you can do very complex code with it, I will start with basic things and then move to more sophisticated applications. Keep in mind that I'm still learning it myself and I'm a lazy bum.
Also, QtQuick was developed to be able to build UIs.
First application: Let's make the QML Viewer, it's in C++, but after this is done you can make everything else in QML and just forget C++.
(I will continue later, wait for the next chapter of our soap opera, for now just download the damn thing and install it if you're interested)
UPDATE 1
(End of UPDATE 1)
UPDATE 2
(End of UPDATE 2)
Second application: Now let's make a menu for our imaginary game.
UPDATE 3
Let's start making a rectangle to our screen, it will be the base of our button.
If we compile we will see it like this, so we have 'x' and 'y' and they are relative to the parent object, then 'height' and 'width' that are in pixels and the 'color' property can be defined like you would in html\css.
Example: ""white"", ""#fff"", ""#ffffff"" or using qt commands like "Qt.rgba(1, 1, 1, 1)"
You can also use "Qt.hsla()", "Qt.darker()", "Qt.lighter()" or "Qt.tint()"
More info here: http://doc.qt.nokia.com/4.7-snapshot/qml-qt.html
Let's try making the rectangle clickable. Add "MouseArea", the "anchors.fill: parent" means it will have the same dimension as it's parent object. The "radius" property will smooth the rectangle's borders.
The "onClicked" event then changes the "parent.color".
As you can see I've clicked on the 'button'.
Now we can try hovering the mouse over the button to change it's color.
First we need to enable hovering it by using the command "hoverEnabled: true" inside the "MouseArea".
The problem with the solution above is that it's changing the color property of the button but sometimes you don't want to directly change it. We can for example make a complex if statement directly on the property and if we do and then force to change it's value, the if statement will be lost.
So let's define our first property, it's boolean and it's named "hover", let's set it to "false".
Then we make the if statement on the color property. If hover is true then change to orange, if hover is not true then change it to white.
And inside the "MouseArea" we then change the "hover" property.
The beauty of it is that Qt will take care of it automatically from now on, whenever the hover property changes, the application gets updated. No need to make functions or connect signals.
You can note from the code above that I also made another rectangle.
I've set it's property "anchors.right" to "parent.right" so it will glue to the right side of our screen.
On our button I've erased the "x" property and set "anchors.horizontalCenter" to "parent.horizontalCenter", so whatever the first Rectangle width size is, the button will always remain at the center.
Let's now make use of other qml files. In qml it's advised to not make a single file with all the code, instead you should use several files each containing modules of your code as to improve performance and code quality.
This means that we can get part of our code, define it on another file and then use it on another qml file the same way you would declare a class and then create objects based on it.
Let's create a MouseOver qml file so whenever we need hovering, we can have it without having to code it again.
And here it is, now let's edit it. Copy our "MouseArea" code to it.
And instead of using "MouseArea" on our main code, let's use "MouseOver" instead.
You can compile it and check that it still acts the same as the previous code, but whenever you need hovering you can declare "MouseOver" instead of "MouseArea".
Put some text inside your button. When you want to change the size of the text you can use "font.pixelSize" or "font.pointSize".
You can read more about it here: http://doc.qt.nokia.com/4.7-snapshot/qml-text.html
See how we make it centered using "anchors.centerIn: parent".
We can try to export our button to another qml file too, let's make it more generic and add a string property.
So this way we export it we can access the text property of the rectangle that we just made and it will automatically update the text property of the text object inside the rectangle.
And so Button.qml is born.
Now check it how our main code got better.
All the properties of the qml file are like default properties that we can override.
So if we want we can set another "height" or "color" if we want on out main code.
I think you're ready to make several buttons for our game menu.
But instead of just repeating "Button" several times, let's make a list of buttons.
We have 3 parts that we need to pay attention here, the first part is the List, I'm going to use a "Repeater", it's a simple list that always shows it's elements, you can use a "ListView" too, this one allows you to move the list with the mouse or keyboard and hide items that are offscreen.
The second part of the list is the data, we define it on a "ListModel" but it can come from several sources like a QStringList from C++ or actual Models from C++ or even XML files.
The third part of the list is how you are going to show it on the screen. First you have to declare a "Component", whatever is inside of the component does not get shown on screen, instead it acts like declaring a class that you haven't created an object yet. We call it a delegate, the "Component" only allows one object inside it, but you can have N objects inside this one object. Let's create the delegate and put our button inside it.
On our "ListModel" we made several items and declared two properties for them, "varText" and "varY" sp we have to use these names on our delegate.
Then in the "Repeater" we just point our model and our delegate.
And voila!
Now we can create a javascript function to know which button was clicked.
It will receive a variable called "buttonName" and the function will be called "menuButtonClicked".
See that I put a "console.log()" command there? This sends a text to Qt Creator so you can check which button you're clicking.
Add the "onClicked" event so that the button sends it's name to the "menuButtonClicked" function.
To make our game menu prettier I'm going to add an image, so I made a "Images" dir inside the "QML" dir and put a "logo.png" there.
And let's go back to the C++ code to add one line so that it knows when we want to quit the game.
We are connecting the view engine quit signal to out main application quit function (slot).
Let's edit the function so that when we click on a button and the button's name is "Quit" it calls "Qt.quit()" signal.
While at it let's add the image, here I didn't need to change it's coordinates but you may need to tweak it a little so it will fit correctly on your window. I've also changed some of the colors.
And here's our first game menu made in QML. The Quit button works, you can hover all the buttons and make buttons if you want adding just a line.
If I've written something dumb please say so I can fix it. Thanks for reading it all up.
Next we will take a look at animations.
(End of UPDATE 3)
Why: Qt uses C++, but if you work with QML you can do all the logic in Javascript, so for those that don't want to learn C++, this might be a easy way to make a simple game and yet have the possibility to work with C++ or C++ libraries if wanted. Oh yeah, you can use Qt on Windows, Linux or Mac OS X.
Prerequisites: Qt 4.8 is a nice start, don't download the online installer, it's shit, download the Qt Library and Qt Creator (IDE) and you have everything you will ever need.
http://releases.qt-project.org/qt4/source/qt-win-opensource-4.8.2-mingw.exe
http://get.qt.nokia.com/qtcreator/qt-creator-win-opensource-2.5.0.exe
This version uses MinGW, there are versions for you to work with Visual Studio, but I've never tried.
About QML: Although QML looks simple you can do very complex code with it, I will start with basic things and then move to more sophisticated applications. Keep in mind that I'm still learning it myself and I'm a lazy bum.
Also, QtQuick was developed to be able to build UIs.
First application: Let's make the QML Viewer, it's in C++, but after this is done you can make everything else in QML and just forget C++.
(I will continue later, wait for the next chapter of our soap opera, for now just download the damn thing and install it if you're interested)
UPDATE 1
Okay, let's open Qt Creator.
Click on 'Create Project'.
Choose 'Qt Console Application'. That's the less bloated one, we will modify it to our needs anyway.
Choose a folder in 'Create in:', the folder must exist so Qt won't create it for you.
What you put in 'Name:' is actually the folder that Qt creates for your project.
Here choose 'Shadow build' so all the garbage the IDE creates goes to a folder other than your source code, define the folder and if it's release or debug. I will be using release.
Just click 'Finish' and voila!
It should look now something like this, minus the divided code window, I divided it to show all the code that was generated by the IDE. You can divide the screen clicking on the buttons where there's a green circle.
You can see that our project has two files, a '.pro' that defines the project and a '.cpp' that is our main file.
First, let's remove the line 'QT += console' because we want a GUI application and change the minus for a plus on the line 'QT -= gui'. You can remove the 'CONFIG' lines too.
Since this isn't a console application also change from 'QCoreApplication' to 'QApplication'.
Also change the '#include' to a more generic one so we can use all the GUI module. Put '#include <QtGui>'.
And we can already show something on screen so I will add a 'QWidget' to it.
One last thing to do is to not show the actual console window.
Go to 'Projects', 'Run Settings' and deselect 'Run in terminal'.
So it should look like this after tidying it up.
I've added the 'QWidget' and then 'showed' it. We usually don't need to show objects but since this is main object of our application we need to do it once.
'QApplication' is the backbone of your application, without it Qt objects won't work.
Now you can compile it clicking on the 'Run' button you can see above.
You will see a blank window. Next I will show you how to add the QML object so we can start coding in QML.
Check out these links if you want to know more about how Qt works:
http://qt-project.org/doc/qt-4.8/
http://qt-project.org/wiki/QtWhitepaper
http://qt-project.org/doc/qt-4.8/signalsandslots.html
This last one is very interesting, it's one way to communicate between C++ and QML
Click on 'Create Project'.
Choose 'Qt Console Application'. That's the less bloated one, we will modify it to our needs anyway.
Choose a folder in 'Create in:', the folder must exist so Qt won't create it for you.
What you put in 'Name:' is actually the folder that Qt creates for your project.
Here choose 'Shadow build' so all the garbage the IDE creates goes to a folder other than your source code, define the folder and if it's release or debug. I will be using release.
Just click 'Finish' and voila!
It should look now something like this, minus the divided code window, I divided it to show all the code that was generated by the IDE. You can divide the screen clicking on the buttons where there's a green circle.
You can see that our project has two files, a '.pro' that defines the project and a '.cpp' that is our main file.
First, let's remove the line 'QT += console' because we want a GUI application and change the minus for a plus on the line 'QT -= gui'. You can remove the 'CONFIG' lines too.
Since this isn't a console application also change from 'QCoreApplication' to 'QApplication'.
Also change the '#include' to a more generic one so we can use all the GUI module. Put '#include <QtGui>'.
And we can already show something on screen so I will add a 'QWidget' to it.
One last thing to do is to not show the actual console window.
Go to 'Projects', 'Run Settings' and deselect 'Run in terminal'.
So it should look like this after tidying it up.
I've added the 'QWidget' and then 'showed' it. We usually don't need to show objects but since this is main object of our application we need to do it once.
'QApplication' is the backbone of your application, without it Qt objects won't work.
Now you can compile it clicking on the 'Run' button you can see above.
You will see a blank window. Next I will show you how to add the QML object so we can start coding in QML.
Check out these links if you want to know more about how Qt works:
http://qt-project.org/doc/qt-4.8/
http://qt-project.org/wiki/QtWhitepaper
http://qt-project.org/doc/qt-4.8/signalsandslots.html
This last one is very interesting, it's one way to communicate between C++ and QML
UPDATE 2
Okay, remember I made the project at 'C:\Codex\Example01' and the 'Shadow Copy' pointed to 'C:\Codex\Build'?
If you did the same thing I did the binary (.exe) is going to end up here:
'C:\Codex\Build\Example01\Release\Example01.exe'
We are going to change that, so let's create some directories!
I made a 'bin' folder inside 'C:\Codex\Example01', and inside it a 'QML' folder.
So the executable and DLLs are going inside BIN and the qml code inside QML.
Now let's add our main qml file.
Right click on your project and select 'Add New...'.
Choose 'Qt' and 'QML File'.
Let's call it 'main.qml' and put it at 'C:\Codex\Example01\bin\QML'.
Now let's fix the 'Working directory' so we find the qml file.
Click on 'Projects' then 'Run Settings' and change it to your bin folder: 'C:\Codex\Example01\bin'.
Now we need to fix where your binary goes when compiled. We will do it on the code.
At the 'Example01.pro' let's change the 'TARGET' to this 'TARGET = ../../../Example01/bin/Example01'.
Remember the binary was being compiled to 'C:\Codex\Build\Example01\Release\Example01.exe'?
So one '..' to exit the 'Release' foder, one to exit the 'Example01' folder, another to exit the 'Build' folder and then we go to the 'Example01/bin/' folder and the last piece is the name of binary.
The 'OTHER_FILES' should have been added automatically when you added the 'main.qml' file.
And finally add the modules declarative and opengl (if you want) to the 'QT' line: 'QT += gui declarative opengl'.
Now let's make the qml viewer.
QDeclarativeView *window = new QDeclarativeView();
Now we need the viewport object, if you want opengl use QGLWidget, if not use a commom QWidget instead.
QGLWidget *viewport = new QGLWidget();
To use it on qml let's disable the autofillbackground option, the QDeclarativeView will do it instead.
viewport->setAutoFillBackground(false);
Now we load the source file that should be in the QML folder, then we put the viewport into the view and show it.
window->setSource(QUrl::fromLocalFile(".\\QML\\main.qml"));
window->setViewport(viewport);
window->show();
The windows is resizable so if you want you can set a fixed, minimum or maximum size like this:
window->setFixedSize(800,600);
window->setMaximumSize(800,600);
window->setMinimumSize(800,600);
Finally we can go to the qml file.
The first object you make is important because it will be your canvas, let's make a 800x600 orange window.
Rectangle
{
width: 800
height: 600
color:"orange"
}
Now compile it and check if you see this window.
Okay, further reading:
http://qt-project.org/doc/qt-4.8/qdeclarativeelements.html
http://qt-project.org/doc/qt-4.8/qdeclarativeexamples.html
If you want to make a hello world add this inside the Rectangle object:
Text
{
text:"HelloWorld"
anchors.centerIn: parent
}
EDIT: Forgot to add the files if you are too lazy to type:
http://purpleorangegames.com/tutorial/Example01_UPDATE2.7z
If you did the same thing I did the binary (.exe) is going to end up here:
'C:\Codex\Build\Example01\Release\Example01.exe'
We are going to change that, so let's create some directories!
I made a 'bin' folder inside 'C:\Codex\Example01', and inside it a 'QML' folder.
So the executable and DLLs are going inside BIN and the qml code inside QML.
Now let's add our main qml file.
Right click on your project and select 'Add New...'.
Choose 'Qt' and 'QML File'.
Let's call it 'main.qml' and put it at 'C:\Codex\Example01\bin\QML'.
Now let's fix the 'Working directory' so we find the qml file.
Click on 'Projects' then 'Run Settings' and change it to your bin folder: 'C:\Codex\Example01\bin'.
Now we need to fix where your binary goes when compiled. We will do it on the code.
At the 'Example01.pro' let's change the 'TARGET' to this 'TARGET = ../../../Example01/bin/Example01'.
Remember the binary was being compiled to 'C:\Codex\Build\Example01\Release\Example01.exe'?
So one '..' to exit the 'Release' foder, one to exit the 'Example01' folder, another to exit the 'Build' folder and then we go to the 'Example01/bin/' folder and the last piece is the name of binary.
The 'OTHER_FILES' should have been added automatically when you added the 'main.qml' file.
And finally add the modules declarative and opengl (if you want) to the 'QT' line: 'QT += gui declarative opengl'.
Now let's make the qml viewer.
QDeclarativeView *window = new QDeclarativeView();
Now we need the viewport object, if you want opengl use QGLWidget, if not use a commom QWidget instead.
QGLWidget *viewport = new QGLWidget();
To use it on qml let's disable the autofillbackground option, the QDeclarativeView will do it instead.
viewport->setAutoFillBackground(false);
Now we load the source file that should be in the QML folder, then we put the viewport into the view and show it.
window->setSource(QUrl::fromLocalFile(".\\QML\\main.qml"));
window->setViewport(viewport);
window->show();
The windows is resizable so if you want you can set a fixed, minimum or maximum size like this:
window->setFixedSize(800,600);
window->setMaximumSize(800,600);
window->setMinimumSize(800,600);
Finally we can go to the qml file.
The first object you make is important because it will be your canvas, let's make a 800x600 orange window.
Rectangle
{
width: 800
height: 600
color:"orange"
}
Now compile it and check if you see this window.
Okay, further reading:
http://qt-project.org/doc/qt-4.8/qdeclarativeelements.html
http://qt-project.org/doc/qt-4.8/qdeclarativeexamples.html
If you want to make a hello world add this inside the Rectangle object:
Text
{
text:"HelloWorld"
anchors.centerIn: parent
}
EDIT: Forgot to add the files if you are too lazy to type:
http://purpleorangegames.com/tutorial/Example01_UPDATE2.7z
Second application: Now let's make a menu for our imaginary game.
UPDATE 3
Let's start making a rectangle to our screen, it will be the base of our button.
If we compile we will see it like this, so we have 'x' and 'y' and they are relative to the parent object, then 'height' and 'width' that are in pixels and the 'color' property can be defined like you would in html\css.
Example: ""white"", ""#fff"", ""#ffffff"" or using qt commands like "Qt.rgba(1, 1, 1, 1)"
You can also use "Qt.hsla()", "Qt.darker()", "Qt.lighter()" or "Qt.tint()"
More info here: http://doc.qt.nokia.com/4.7-snapshot/qml-qt.html
Let's try making the rectangle clickable. Add "MouseArea", the "anchors.fill: parent" means it will have the same dimension as it's parent object. The "radius" property will smooth the rectangle's borders.
The "onClicked" event then changes the "parent.color".
As you can see I've clicked on the 'button'.
Now we can try hovering the mouse over the button to change it's color.
First we need to enable hovering it by using the command "hoverEnabled: true" inside the "MouseArea".
The problem with the solution above is that it's changing the color property of the button but sometimes you don't want to directly change it. We can for example make a complex if statement directly on the property and if we do and then force to change it's value, the if statement will be lost.
So let's define our first property, it's boolean and it's named "hover", let's set it to "false".
Then we make the if statement on the color property. If hover is true then change to orange, if hover is not true then change it to white.
And inside the "MouseArea" we then change the "hover" property.
The beauty of it is that Qt will take care of it automatically from now on, whenever the hover property changes, the application gets updated. No need to make functions or connect signals.
You can note from the code above that I also made another rectangle.
I've set it's property "anchors.right" to "parent.right" so it will glue to the right side of our screen.
On our button I've erased the "x" property and set "anchors.horizontalCenter" to "parent.horizontalCenter", so whatever the first Rectangle width size is, the button will always remain at the center.
Let's now make use of other qml files. In qml it's advised to not make a single file with all the code, instead you should use several files each containing modules of your code as to improve performance and code quality.
This means that we can get part of our code, define it on another file and then use it on another qml file the same way you would declare a class and then create objects based on it.
Let's create a MouseOver qml file so whenever we need hovering, we can have it without having to code it again.
And here it is, now let's edit it. Copy our "MouseArea" code to it.
And instead of using "MouseArea" on our main code, let's use "MouseOver" instead.
You can compile it and check that it still acts the same as the previous code, but whenever you need hovering you can declare "MouseOver" instead of "MouseArea".
Put some text inside your button. When you want to change the size of the text you can use "font.pixelSize" or "font.pointSize".
You can read more about it here: http://doc.qt.nokia.com/4.7-snapshot/qml-text.html
See how we make it centered using "anchors.centerIn: parent".
We can try to export our button to another qml file too, let's make it more generic and add a string property.
So this way we export it we can access the text property of the rectangle that we just made and it will automatically update the text property of the text object inside the rectangle.
And so Button.qml is born.
Now check it how our main code got better.
All the properties of the qml file are like default properties that we can override.
So if we want we can set another "height" or "color" if we want on out main code.
I think you're ready to make several buttons for our game menu.
But instead of just repeating "Button" several times, let's make a list of buttons.
We have 3 parts that we need to pay attention here, the first part is the List, I'm going to use a "Repeater", it's a simple list that always shows it's elements, you can use a "ListView" too, this one allows you to move the list with the mouse or keyboard and hide items that are offscreen.
The second part of the list is the data, we define it on a "ListModel" but it can come from several sources like a QStringList from C++ or actual Models from C++ or even XML files.
The third part of the list is how you are going to show it on the screen. First you have to declare a "Component", whatever is inside of the component does not get shown on screen, instead it acts like declaring a class that you haven't created an object yet. We call it a delegate, the "Component" only allows one object inside it, but you can have N objects inside this one object. Let's create the delegate and put our button inside it.
On our "ListModel" we made several items and declared two properties for them, "varText" and "varY" sp we have to use these names on our delegate.
Then in the "Repeater" we just point our model and our delegate.
And voila!
Now we can create a javascript function to know which button was clicked.
It will receive a variable called "buttonName" and the function will be called "menuButtonClicked".
See that I put a "console.log()" command there? This sends a text to Qt Creator so you can check which button you're clicking.
Add the "onClicked" event so that the button sends it's name to the "menuButtonClicked" function.
To make our game menu prettier I'm going to add an image, so I made a "Images" dir inside the "QML" dir and put a "logo.png" there.
And let's go back to the C++ code to add one line so that it knows when we want to quit the game.
We are connecting the view engine quit signal to out main application quit function (slot).
Let's edit the function so that when we click on a button and the button's name is "Quit" it calls "Qt.quit()" signal.
While at it let's add the image, here I didn't need to change it's coordinates but you may need to tweak it a little so it will fit correctly on your window. I've also changed some of the colors.
And here's our first game menu made in QML. The Quit button works, you can hover all the buttons and make buttons if you want adding just a line.
If I've written something dumb please say so I can fix it. Thanks for reading it all up.
Next we will take a look at animations.
(End of UPDATE 3)