- read

Qt Series S01E04: To Get Off to a Good Start

Fabio Cocci 34

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 start a project from scratch without the help of the QtCreator.

Photo by Max Duzij on Unsplash

Git

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 ones and it is very easy 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 had the build folder, the Makefile, and various Qt files to 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 contain 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 which is 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 guigreaterThan(QT_MAJOR_VERSION, 4): QT += widgetsCONFIG += c++11TARGET = myprogramDESTDIR=build
OBJECTS_DIR=build
MOC_DIR=build
UI_DIR=build
RCC_DIR=build
SOURCES += \
src/main.cpp \
src/mainwindow.cpp
HEADERS += \
src/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
src/main.cpp
src/mainwindow.cpp
src/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 have now all the basic 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 MyProgram.pro
make
build/myprogram

or cmake.

cmake -B build/
make
build/myprogram

Wrap up

We have now the basic structure to start our application.

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

We can now 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.