Styling in Qt Modeling Language (QML)
Qt Meta Language or Qt Modeling Language (QML) is a JavaScript-inspired user interface markup language that’s used by Qt to design user interfaces. Qt provides you with Qt Quick Components (widgets powered by the QML technology) to easily design touch-friendly UI without C++ programming. We will learn more about how to use QML and Qt Quick Components to design our program’s UI by following the steps provided in this recipe.
How to do it…
Follow these steps to learn about styling in QML:
- Since Qt 6, The Qt Company has released a separate program called Qt Design Studio for developing Qt Quick applications. It’s intended to separate the different tasks of designers and programmers. So, if you’re a GUI designer, you should use Qt Design Studio, while sticking to Qt Creator if you’re a programmer. Once you have installed and opened Qt Design Studio, create a new project by pressing on the big Create Project… button or by going to File | New Project… from the top menu:
Figure 1.19 – Creating a new QML project in Qt Design Studio
- Once the New Project window appears, key in the default width and height of your project window and insert a name for your project. Then, select the directory where you want your project to be created, select a default GUI style, pick a target Qt version, and click the Create button. Your Qt Quick project will now be created by Qt Design Studio.
- There are some differences between a QML project and a C++ Qt project. You will see an
App.qml
file inside the project resource. This.qml
file is the UI description file that’s written using the QML markup language. If you double-click themain.qml
file, Qt Creator will open the script editor and you will see something like this:import QtQuick 6.2 import QtQuick.Window 6.2 import MyProject Window { width: mainScreen.width height: mainScreen.height visible: true title: "MyProject" Screen01 { id: mainScreen } }
- This file tells Qt to create a window that loads the Screen01 user interface and a window title with your project name. The Screen01 interface comes from another file called Screen01.ui.qml.
- If you open the
main.cpp
file located in thescr
folder in your project, you will see the following line of code:QQmlApplicationEngine engine; const QUrl url(u"qrc:Main/main.qml"_qs);
- The preceding code tells Qt’s QML engine to load the
main.qml
file when the program starts. If you want to load the other.qml
file, you know where to look for the code. Thesrc
folder is hidden from your Qt Design Studio project; you can look for it inside your project directory. - If you build the project now, all you’ll get is a huge window with simple text and a push button that says Press me. The window’s background color and the text will change when you press the push button:
Figure 1.20 – Your first Qt Quick program
- To add UI elements, we’ll create a Qt Quick UI File by going to File | New File… and selecting Qt Quick UI File under the Files and Classes | Qt Quick Files category:
Figure 1.21 - Creating a new Qt Quick UI file
- Set Component name to
Main
, followed by clicking the Finish button:
Figure 1.22 – Giving your Qt Quick component a meaningful name
- A new file called
Main.ui.qml
has been added to your project resources. Try to open theMain.ui.qml
file by double-clicking on it, if it hasn’t been automatically opened by Qt Design Studio upon creation. You will see a completely different UI editor compared to what we had for the C++ project in the previous recipes. - Let’s open
App.qml
and replace Screen01 with Main, like so:Main { id: mainScreen }
- When
App.qml
is loaded by the QML engine, it will also importMain.ui.qml
into the UI sinceMain
is now being called in theApp.qml
file. Qt will check whetherMain
is a valid UI by searching for its.qml
file based on the naming convention. This concept is similar to the C++ project we completed in all our previous recipes; theApp.qml
file acts like themain.cpp
file andMain.ui.qml
acts like theMainWindow
class. You can also create other UI templates and use them inApp.qml
. Hopefully, this comparison will make it easier to understand how QML works. - Open
Main.ui.qml
. You should see only one item listed in the Navigator window: Item. This is the base layout of the window, which shouldn’t be deleted. It is similar to centralWidget, which we used in the previous recipe. - The canvas is empty at the moment, so let’s drag a Mouse Area item and Text items to the canvas from the QML Types panel on the left. Resize Mouse Area so that it fills the entire canvas. Also, make sure that both Mouse Area and the Text items are being placed under the Item item in the Navigator panel, as shown in the following screenshot:
Figure 1.23 – Dragging and dropping a mouse area and text items onto the canvas
- The Mouse Area item is an invincible item that gets triggered when the mouse is clicking on it, or when a finger is touching it (for mobile platforms). The Mouse Area item is also used in a button component, which we will be using in a while. The Text item is self-explanatory: it is a label that displays a block of text in the application.
- On the Navigator window, we can hide or show an item by clicking on the icon that resembles an eye beside the item. When an item is hidden, it will not appear on the canvas or the compiled application. Just like the widgets in a C++ Qt project, Qt Quick Components are arranged in a hierarchy based on the parent-child relationship. All the child items will be placed under the parent item with an indented position. In our case, we can see that the Mouse Area and Text elements are positioned slightly to the right compared to the Item item because they are both children of the Item element. We can rearrange the parent-child relationship, as well as their position in the hierarchy, by using a click-and-drag method from the Navigator window. You can try clicking on the Text item and dragging it on top of the mouse area. You will then see that the Text item has changed its position and is now located beneath the mouse area with a wider indentation:
Figure 1.24 – Rearranging the parent-child relationship between items
- We can rearrange them by using the arrow buttons located at the top of the Navigator window, as shown in the preceding screenshot. Anything that happens to the parent item will also affect all its children, such as moving the parent item, and hiding and showing the parent item.
Note
You can pan around the canvas view by holding the middle mouse button (or mouse scroll) while moving your mouse around. You can also zoom in and out by scrolling your mouse while holding the Ctrl key on your keyboard. By default, scrolling your mouse will move the canvas view up and down. However, if your mouse cursor is on top of the horizontal scroll bar of the canvas, scrolling the mouse will move the view to the left and right.
- Delete both the Mouse Area item and Text items as we will be learning how to create a user interface from scratch using QML and Qt Quick.
- Set the Item element’s size to
800 x 600
as we’re going to need a bigger space for the widgets. - Copy the images we used in the previous C++ project, in the Using resources in style sheets recipe, over to the QML project’s folder since we are going to recreate the same login screen with QML.
- Add the images to the resource file so that we can use them for our UI.
- Open Qt Design Studio and switch to the Resources window. Click and drag the background image directly to the canvas. Switch over to the Layout tab on the Properties pane and click the fill anchor button, indicated here by a red circle. This will make the background image always stick to the window size:
Figure 1.25 – Selecting the fill anchor button to make the item follow the size of its parent object
- Click and drag a Rectangle component from the Library window to the canvas. We will use this as the top panel for our program.
- For the top panel, enable the top anchor, left anchor, and right anchor so that the panel sticks to the top of the window and follows its width. Make sure all the margins are set to zero.
- Go to the Color property of the top panel and select Gradient. Set the first color to
#805bcce9
and the second color to#80000000
. This will create a half-transparent panel with a blue gradient. - Add a Text widget to the canvas and make it a child of the top panel. Set its text property to the current date and time (for example,
Wednesday, 25-10-2023 3:14 PM
) for display purposes. Then, set the text color to white. - Switch over to the Layout tab and enable the top anchor and left anchor so that the text widget will always stick to the top-left corner of the screen.
- Add a Mouse Area item to the screen and set its size to
50 x 50
. Then, make it a child of the top panel by dragging it on top of the top panel in the Navigator window. - Set the color of the mouse area to blue (
#27a9e3
) and set its radius to2
to make its corners slightly rounded. Enable the top anchor and right anchor to make it stick to the top-right corner of the window. Set the top anchor’s margin to8
and the right anchor’s margin to10
to create some space. - Open the Resources window and drag the shutdown icon to the canvas. Make it a child of the Mouse Area item we created a moment ago. Then, enable the fill anchor to make it fit the size of the mouse area.
- Phew – that’s a lot of steps! Now, your items should be arranged as follows in the Navigator window:
Figure 1.26 – Be cautious about the parent-child relationship between items
- The parent-child relationship and the layout anchors are both very important to keep the widgets in the correct positions when the main window changes its size. Your top panel should look something like this:
Figure 1.27 – Completing the top banner design
- Let’s work on the login form. Add a new Rectangle to the canvas by dragging it from the Library window. Resize the rectangle to
360 x 200
and set its radius to15
. - Set its color to
#80000000
; this will change it to black with 50% transparency. - Enable the vertical center anchor and the horizontal center anchor to make the rectangle always align with the center of the window. Then, set the margin of the vertical center anchor to
100
so that it moves slightly lower to the bottom. This will ensure we have the space to place the logo. The following screenshot illustrates the settings for Anchors:
Figure 1.28 – Setting the alignment and margin
- Add the text objects to the canvas. Make them children of the login form (the Rectangle widget) and set their text properties to
Username:
andPassword:
. Change their text color to white and position them accordingly. We don’t need to set a margin this time because they will follow the rectangle’s position. - Add two text input objects to the canvas and place them next to the text widgets we just created. Make sure the text input is also a child of the login form. Since the text input doesn’t contain any background color property, we need to add two rectangles to the canvas to use as their background.
- Add two rectangles to the canvas and make each of them a child of one of the text inputs we just created. Set the radius property to
5
to give them some rounded corners. After that, enable fill anchors on both of the rectangles so that they will follow the size of the text input widgets. - Now, let’s create the login button beneath the password field. Add a mouse area to the canvas and make it a child of the login form. Resize it to your preferred dimension and move it into place.
- Since the mouse area does not contain any background color property, we need to add a Rectangle widget and make it a child of the mouse area. Set the color of the rectangle to blue (
#27a9e3
) and enable the fill anchor so that it fits nicely with the mouse area. - Add a text object to the canvas and make it a child of the login button. Change its text color to white and set its text property to
Login
. Finally, enable the horizontal center anchor and the vertical center anchor so that they align with the center of the button. - You will now get a login form that looks pretty similar to the one we made in the C++ project:
Figure 1.29 – Final design of the login form
- Now, it’s time to add the logo, which is very simple. Open the Resources window and drag the logo image to the canvas.
- Make it a child of the login form and set its size to
512
x 200
. - Position it on top of the login form. With that, you’re done.
- This is what the entire UI looks like when compiled. We have successfully recreated the login screen from the C++ project, but this time, we did it with QML and Qt Quick:
Figure 1.30 – The final result
How it works…
The Qt Quick editor uses a very different approach for placing widgets in the application compared to the form editor. The user can decide which method is best suited to their purposes. The following screenshot shows what the Qt Quick Designer looks like:
Figure 1.31 – Overview of Qt Design Studio’s user interface
Let’s look at the various elements of the editor’s UI:
- Navigator: The Navigator window displays the items in the current QML file as a tree structure. It’s similar to the object operator window in the other Qt Designer we used in the Using style sheets with Qt Designer recipe.
- Library: The Library window displays all the Qt Quick Components or Qt Quick Controls available in QML. You can click and drag it to the canvas window to add to your UI. You can also create your own custom QML components and display them here.
- Assets: The Assets window displays all the resources in a list that can then be used in your UI design.
- Add Modules: The Add Modules button allows you to import different QML modules into your current QML file, such as a Bluetooth module, a WebKit module, or a positioning module, to add additional functionality to your QML project.
- Properties: Similar to the Property Editor area we used in the previous recipe, the Properties pane in QML Designer displays the properties of the selected item. You can also change the properties of the items in the code editor.
- Canvas: The canvas is the working area where you create QML components and design applications.
- Workspace selector: The workspace selector area displays the different layouts available in the Qt Design Studio editor, allowing the user to select the workspace that suits their needs.
- Style selector: This selector is where you can select a different style to preview how your application will look when running on a specific platform. This is very useful when developing cross-platform applications.