background-shape
feature-image

Qt Series S01E04: To Get Off to a Good Start

Starting a new Qt project can be as easy as starting the QtCreator and clicking the New Project QAction. In this episode, we will see how to create a project from scratch without the help of the QtCreator.

To start our project, we need a version control software. We will use Git in this example because it is one of the most used and is straightforward to grasp.

First, we create a folder and then initialize our Git repository.

mkdir MyProgram
cd MyProgram
git init

Then we create the file .gitignore to specify untracked files that Git will ignore. We add the build folder, the Makefile, and various Qt files in the file that we don’t want to track.

*build*
Makefile
*.pro.user*
*.user
.qmake.stash

Folder architecture

We construct the backbone of our project by creating two folders: src/ that will contain the source files (.cpp, .h…) resources/ that will have additional files (images, sounds …).

mkdir src
mkdir resources

Clang format

To enforce the code formatting, we use clang-format. The formatting rules are written in the .clang-format file that we generate using the llvm formatting convention.

clang-format -style=llvm -dump-config > .clang-format

Application file

The first file to create is the main.cpp file that contains the main function called at the program startup. In this file, we initialize the QApplication that will handle the event loop and all events from the window system. Then we initialize the MainWindow object w, a subclass of a QMainWindow, the parent widget for our application.

#include "mainwindow.h"
#include <QApplication>
int main(int argc, char *argv[]) {
QApplication a(argc, argv);
MainWindow w;
w.show();
return a.exec();
}

The second file to create is the implementation of the MainWindow by subclassing the QMainWindow widget.

src/mainwindow.h

#ifndef MAINWINDOW_H
#define MAINWINDOW_H
#include <QMainWindow>
class MainWindow : public QMainWindow {
Q_OBJECT
public:
MainWindow(QWidget *parent = nullptr);
~MainWindow();
};
#endif

src/mainwindow.cpp

#include "mainwindow.h"
MainWindow::MainWindow(QWidget *parent) : QMainWindow(parent) {}
MainWindow::~MainWindow() {}

Finally, we create the resource resources.qrc file that will list all the resources used by the program (images, sounds, etc.) that can be called in the code source using the “:/path” syntax.

resources/resources.qrc
<!DOCTYPE RCC><RCC version="1.0">
   <qresource prefix='/'>
   </qresource>
</RCC>

Compilation file

Finally, we need a build automation tool to generate the Makefile to compile our program. We can either use qmake or cmake.

MyProgram.pro

QT       += core gui
greaterThan(QT_MAJOR_VERSION, 4): QT += widgets
CONFIG += c++11
TARGET = myprogram
DESTDIR=build
OBJECTS_DIR=build
MOC_DIR=build
UI_DIR=build
RCC_DIR=build
SOURCES += \
   main.cpp \
   mainwindow.cpp
HEADERS += \
   mainwindow.h
RESOURCES += \
   ../resources/resources.qrc

CMakeLists.txt:

cmake_minimum_required(VERSION 3.5)
project(myprogram VERSION 0.1 LANGUAGES CXX)
set(CMAKE_INCLUDE_CURRENT_DIR ON)
set(CMAKE_AUTOUIC ON)
set(CMAKE_AUTOMOC ON)
set(CMAKE_AUTORCC ON)
set(CMAKE_CXX_STANDARD 11)
set(CMAKE_CXX_STANDARD_REQUIRED ON)
find_package(QT NAMES Qt6 Qt5 COMPONENTS Widgets REQUIRED)
find_package(Qt${QT_VERSION_MAJOR} COMPONENTS Widgets REQUIRED)
set(PROJECT_SOURCES
        main.cpp
        mainwindow.cpp
        mainwindow.h
)
qt_add_resources(../resources/resources.qrc
)
if(${QT_VERSION_MAJOR} GREATER_EQUAL 6)
    qt_add_executable(myprogram
        MANUAL_FINALIZATION
        ${PROJECT_SOURCES}
    )
else()
        add_executable(myprogram
             ${PROJECT_SOURCES}
        )
endif()
target_link_libraries(myprogram PRIVATE Qt${QT_VERSION_MAJOR}::Widgets)
set_target_properties(myprogram PROPERTIES
    MACOSX_BUNDLE_GUI_IDENTIFIER my.example.com
    MACOSX_BUNDLE_BUNDLE_VERSION ${PROJECT_VERSION}
    MACOSX_BUNDLE_SHORT_VERSION_STRING
${PROJECT_VERSION_MAJOR}.${PROJECT_VERSION_MINOR}
)
if(QT_VERSION_MAJOR EQUAL 6)
     qt_finalize_executable(myprogram)
endif()

Compilation

We now have all the essential files to compile and run our program. First, we need to enforce the code formatting by running clang-format.

clang-format src/*

Then we compile the program either using qmake,

qmake src/MyProgram.pro
make
build/myprogram

or cmake.

cmake src/CMakeLists.txt -B build/
make
build/myprogram

Wrap up

The basic structure to start our application is created.

MyProgram/
├─ .clang-format
├─ .gitignore
├─ .git/
├─ src/
│  ├─ main.cpp
│  ├─ mainwindow.cpp
│  ├─ mainwindow.h
│  ├─ CMakeLists.txt
│  ├─ MyProgram.pro
├─ resources/
│  ├─ ressources.qrc

We can commit our changes using Git

git add -A
git commit -m "Add basic structure"

Conclusion

In this episode, we have created a basic Qt application from scratch that we can compile using either qmake or make. We can see that a basic Qt project doesn’t need a lot of files and only two widgets: the QApplication necessary for all Qt GUI programs and a QMainWindow that we now have to implement at our convenience to fill our program expectations. Going without the QtCreator is easily possible if you prefer using our favorite text editor or IDE and can help us understand better how Qt tools work. In the next episode, we will see how to upload our repository on GitHub and check the code formatting automatically using GitHub Actions.