Chapter 3. Working with Qt

Have you ever been in a situation where Qt “won’t build,” the debugger stays silent, and the project suddenly becomes a collection of disconnected files? This is where many people lose hours—and start “fixing” code when the problem is actually hidden in the tools and build system.

This chapter reveals what professional developers consider basic Qt project hygiene: why the build system matters more than the first class and how one correct configuration saves days. You’ll discover where the real boundary lies between “quickly building a prototype” and “maintaining a project for years.”

Here you’ll find the minimal CMakeLists.txt for Qt6, the logic “behind the scenes” (MOC/RCC), and 5 key mappings between qmake and CMake that speed up migration. Plus—practical debugging techniques: from qDebug/qWarning/qFatal to redirecting logs to files and disabling debug output in release builds.

Chapter Self-Check

Why has CMake become the main build system in Qt6, even though qmake is still supported?Answer
Correct answer: CMake provides better cross-platform development, simplifies integration with other libraries, and is a modern industry standard, making projects more flexible and scalable.
What happens if you forget to add the Q_OBJECT macro in a class that uses signals and slots?Answer
Correct answer: MOC won’t create the necessary additional code to support the signals/slots mechanism, leading to compilation errors or non-working connections. Using qobject_cast for type casting will also become impossible.
Why compile resources (images, files) directly into the executable instead of storing them as separate files?Answer
Correct answer: This guarantees that necessary resources are always available and cannot be accidentally deleted or moved by the user, improving application reliability and simplifying distribution.
What real problem does the multi-IDE approach solve in Qt application development?Answer
Correct answer: It allows using the advantages of each environment simultaneously: Qt Creator for Qt-specific features, VS Code/Cursor for AI tools and navigation, Visual Studio/XCode for debugging, significantly speeding up development in large teams.
What’s the practical difference between calling qDebug() and directly creating a QDebug(QtDebugMsg) object?Answer
Correct answer: Functionally they’re identical, but qDebug() is more compact and convenient—it’s a wrapper function that automatically creates a QDebug object with the appropriate message type.
Why is comparing two floating-point numbers with the == operator considered an error, and how does qFuzzyCompare() solve this?Answer
Correct answer: Due to how floating-point numbers are represented in memory, rounding errors occur. qFuzzyCompare() uses relative comparison accounting for tolerance, increasing precision for smaller values.
When does using aliases in qrc files become especially useful?Answer
Correct answer: When resource files are in deeply nested directories with long paths—aliases allow short references (e.g., “:/open.png” instead of “:/very/long/path/images/open.png”), making code readable and convenient.
How do you redirect output from qDebug(), qWarning(), and qFatal() functions to a file instead of console, and why is this needed?Answer
Correct answer: By using qInstallMessageHandler() with a custom function that writes messages to a file. This allows collecting error logs from users and testers for subsequent problem analysis.
What happens if you call the qFatal() function as opposed to qDebug() or qWarning()?Answer
Correct answer: After outputting the message, qFatal() immediately terminates the entire application, while qDebug() and qWarning() only output information and continue program execution.
Why is it NOT recommended to include moc files at the end of the main file via #include “main.moc”?Answer
Correct answer: It’s better for moc files to be compiled separately and linked by the linker—this improves project structure and speeds up rebuilding. Including in main.cpp is acceptable only for simple demo programs.
How do you hide all qDebug() debug messages in the release version while keeping them in debug builds?Answer
Correct answer: Create an empty dummyOutput() function and install it via qInstallMessageHandler() inside conditional compilation #ifndef QT_DEBUG, so debug messages are ignored only in release builds.
What three commands are sufficient to create an executable program from C++ source files when using qmake?Answer
Correct answer: qmake -project (creates pro file), qmake (creates Makefile), make (compiles the project). This demonstrates Qt’s build process automation.
What’s the practical advantage of using Qt types (qint32, quint64) instead of standard C++ types (int, unsigned long long)?Answer
Correct answer: Qt types guarantee fixed size regardless of platform (e.g., qint32 is always 32 bits), ensuring predictability in cross-platform development and when working with binary data.

Practical Exercises

Easy Level

Application with Embedded Resources
Create a Qt application with CMake that displays a window with an image loaded from embedded resources. Add 2-3 images to a qrc file, use aliases to simplify paths. Output Qt version and plugin path information to qDebug() using QLibraryInfo.
Hints: Create a resources.qrc file describing images. In CMakeLists.txt use qt_add_resources(). To load an image: QPixmap(“:/alias_name”). Use QLibraryInfo::version() and QLibraryInfo::path() to get Qt information.
Medium Level

Logging System with Categories
Implement a logging system that writes qDebug(), qWarning(), qCritical(), and qInfo() messages to a file with timestamps and categories. Add the ability to filter messages by importance level (enable/disable Debug message output). Create a macro that automatically disables all logs in release builds.
Hints: Use qInstallMessageHandler() with a custom handler function. In the function, check message type (QtMsgType) and write to QFile with QTextStream. Use QDateTime::currentDateTime() for timestamps. For conditional compilation, use #ifndef QT_DEBUG.
Hard Level

Project Migration from qmake to CMake
Take an existing Qt5 project with qmake (you can create your own with 5-7 files: main.cpp, several classes with headers, a qrc file with resources, a ui file from Qt Designer). Manually create an equivalent CMakeLists.txt for Qt6 using the mapping table from the chapter. Ensure the project builds and works identically. Add automatic MOC and resource processing.
Hints: Start with cmake_minimum_required() and find_package(Qt6). Use qt_add_executable() instead of TEMPLATE=app. Pass all SOURCES and HEADERS as function arguments. Convert QT+=widgets to find_package(Qt6 COMPONENTS Widgets) + target_link_libraries(). Enable CMAKE_AUTOMOC for automatic MOC processing. For UI files, use CMAKE_AUTOUIC.

💬 Join the Discussion!

Got a handle on CMake and qmake build systems? Successfully set up a logging system?

Have questions about migrating from Qt5 to Qt6, how MOC works, or using resources?

Share your experience transitioning to CMake, tell us about solutions you’ve found, or ask questions—your experience can help other readers master Qt tools faster!

Leave a Reply

Your email address will not be published. Required fields are marked *