Skip to main content Qt C++ Development Guide | IoT Worker

Qt C++ Development Guide

Why Learn Qt C++

Qt is a mature, open-source C++ UI framework with commercial support. It is especially well suited for industrial, medical, and other device-oriented software.

  • Stability and maturity: Qt has a long production track record and a large ecosystem
  • Cross-platform advantage: one source tree can build applications for Windows, macOS, and Linux
  • Command-line support: Qt is not limited to GUI apps; it also works well for console tools
  • Learning value: it has rich documentation, clear conventions, and practical examples that help deepen C++ skills

Development Environment

Installing Qt Libraries and Tools

  • Use the Qt Online Installer
  • On Linux, package managers such as apt can install the distribution-provided build
  • You can also build from source. The example below uses Linux:
# Install dependencies
sudo apt install -y build-essential libgl1-mesa-dev \
    libfontconfig1-dev \
    libfreetype6-dev \
    libx11-dev \
    libx11-xcb-dev \
    libxext-dev \
    libxfixes-dev \
    libxi-dev \
    libxrender-dev \
    libxcb1-dev \
    libxcb-cursor-dev \
    libxcb-glx0-dev \
    libxcb-keysyms1-dev \
    libxcb-image0-dev \
    libxcb-shm0-dev \
    libxcb-icccm4-dev \
    libxcb-sync-dev \
    libxcb-xfixes0-dev \
    libxcb-shape0-dev \
    libxcb-randr0-dev \
    libxcb-render-util0-dev \
    libxcb-util-dev \
    libxcb-xinerama0-dev \
    libxcb-xkb-dev \
    libxkbcommon-dev \
    libxkbcommon-x11-dev \
    libssl-dev libclang-dev libbluetooth-dev

# Configure
./configure -release -prefix /opt/qt/6.5 \
    -no-accessibility -openssl-linked \
    -disable-deprecated-up-to 0x060500 \
    -skip qt3d \
    -skip qt5compat \
    -skip qtactiveqt \
    -skip qtdatavis3d \
    -skip qtdeclarative \
    -skip qtdoc \
    -skip qtlocation \
    -skip qtlottie \
    -skip qtmqtt \
    -skip qtopcua \
    -skip qtscxml \
    -skip qtquick3d \
    -skip qtquick3dphysics \
    -skip qtquickeffectmaker \
    -skip qtquicktimeline \
    -skip qtwebengine \
    -skip qtwebview \
    -skip qtvirtualkeyboard \
    -- -DOPENSSL_USE_STATIC_LIBS=ON

# Build and install
cmake --build . --parallel && sudo cmake --install .
cmake --build . --target docs && sudo cmake --build . --target install_docs

# Add Qt to PATH
echo 'export PATH="/opt/qt/6.5/bin:$PATH"' >> ~/.profile

Code Editing and Compilation

  • Use Qt Creator or a common editor such as VSCode
  • A minimal CMake setup looks like this:
cmake_minimum_required(VERSION 3.14)
project(test LANGUAGES CXX)
set(CMAKE_AUTOUIC ON)
set(CMAKE_AUTOMOC ON)
set(CMAKE_AUTORCC ON)
set(CMAKE_CXX_STANDARD 17)
set(CMAKE_CXX_STANDARD_REQUIRED ON)
find_package(Qt6 REQUIRED COMPONENTS Core)
link_libraries(Qt6::Core)
add_executable(test main.cpp)

main.cpp:

#include <QCoreApplication>
#include <QDate>
#include <QTimer>

int main(int argc, char* argv[])
{
    QCoreApplication a(argc, argv);
    a.setApplicationVersion(QDate::currentDate().toString("yyyyMMdd"));
    a.setOrganizationName("iotworker");

    qInfo() << "App:" << a.applicationName() << "Version:" << a.applicationVersion() << "Pid:" << a.applicationPid();
    qInfo() << "Organization:" << a.organizationName();

    a.connect(&a, &QCoreApplication::aboutToQuit, []() {
        qDebug() << "about to quit";
    });
    QTimer::singleShot(3000, &a, QCoreApplication::quit);

    return a.exec();
}

Core Concepts

Signals and Slots

Signals and slots are one of Qt Core’s basic features for object-to-object communication. They work like callbacks, but they are usually easier to read and connect.

// test.h
#include <QDebug>
#include <QObject>

class Counter : public QObject {
    Q_OBJECT

public slots:
    void setValue(int value)
    {
        mValue = value;
        qDebug() << objectName() << __func__ << value;
        emit valueChanged(value);
    }

signals:
    void valueChanged(int value);

private:
    int mValue = 0;
};

// main.cpp
Counter a, b;
a.setObjectName("A");
b.setObjectName("B");

QObject::connect(&a, &Counter::valueChanged, &b, &Counter::setValue);

a.setValue(1);
  • Signal methods are public, but they are usually intended for the class itself and its subclasses
  • A signal has no return value and usually does not take parameters
  • Signals are preprocessed by moc at build time
  • After emit, connected slots are called in connection order, except for queued connections
  • A slot is an ordinary C++ function and can be called directly

QObject

QObject is an important base class in Qt. It provides signals and slots, the property system, event handling, and object lifetime management.

Important Macros

  • Q_OBJECT: the core macro for the meta-object system; subclasses of Qt types usually need it
  • Q_CLASSINFO: attaches custom key-value metadata to a class
  • Q_ENUM: exposes enum values to the Qt meta-object system and string conversion

Important Members

// Connect signals and slots
QObject::connect(const QObject *sender, const char *signal,
    const QObject *receiver, const char *method,
    Qt::ConnectionType type = Qt::AutoConnection);

// Meta object access
const QMetaObject QObject::staticMetaObject;

// Signals
void destroyed(QObject *obj = nullptr);
void objectNameChanged(const QString &objectName);

// Slots
void deleteLater();

// Common functions
bool blockSignals(bool block);
const QObjectList &children() const;
void setParent(QObject *parent);
QObject *parent() const;
void dumpObjectInfo();
void dumpObjectTree();
void setObjectName(const QString &name);
QString objectName() const;
bool setProperty(const char *name, const QVariant &value);
QVariant property(const char *name) const;

QCoreApplication

QCoreApplication is the core class for non-GUI applications and the base class of QApplication.

Application Configuration

QCoreApplication a(argc, argv);
a.setApplicationName("test");
a.setApplicationVersion("0.1");
a.setOrganizationName("iotworker");
a.setOrganizationDomain("test.com");

qDebug() << a.applicationDirPath();
qDebug() << a.applicationName();
qDebug() << a.applicationVersion();

Argument Parsing

QCommandLineParser parser;
parser.setApplicationDescription("test");
parser.addHelpOption();
parser.addVersionOption();
parser.addOptions({
    { "s", "short option", "valueName", "defaultValue" },
    { "long", "long option" }
});
parser.addPositionalArgument("pos1", "position args");
parser.process(a);

if (parser.isSet("s")) {
    qDebug() << parser.value("s");
}

Logging System

Q_LOGGING_CATEGORY(test, "Test")

static void myLogOutput(QtMsgType type, const QMessageLogContext& context, const QString& msg)
{
    // Custom log format
}

int main(int argc, char* argv[])
{
    qInstallMessageHandler(myLogOutput);
    QLoggingCategory::setFilterRules("*.debug=false\nTest.critical=false");

    qCDebug(test, "debug message");
    qCCritical(test, "error message");
}

Timers

QTimer timer;
QObject::connect(&timer, &QTimer::timeout, []() {
    qDebug() << "interval timeout";
});

QTimer::singleShot(3000, [&timer]() {
    qDebug() << "single shot timeout";
    timer.start(1000);
});

Common Modules

QDateTime

QDateTime is used for date and time handling.

// Current time
auto now = QDateTime::currentDateTime();
qDebug() << now;

// Timestamp conversion
qDebug() << QDateTime::fromMSecsSinceEpoch(1687907736713, QTimeZone::UTC);
qDebug() << now.toMSecsSinceEpoch();

// String conversion
qDebug() << QDateTime::fromString("20230628", "yyyyMMdd");
qDebug() << now.toString("yyyy/MM/dd HH:mm:ss.zzz");

// Time arithmetic
qDebug() << now.addDays(1);
qDebug() << now.daysTo(now.addYears(1));

JSON and CBOR Handling

JSON

// Parse JSON
QJsonDocument js = QJsonDocument::fromJson(js_str);
QJsonObject root_obj = js.object();

// Modify JSON
root_obj["new"] = true;
root_obj.remove("isStudent");
root_obj["age"] = 30;

// Iterate
for (auto&& i : root_obj["languages"].toArray()) {
    qDebug() << i;
}

// Serialize
qDebug() << QJsonDocument(root_obj).toJson().data();

CBOR

// Create CBOR
QCborMap root_obj = {
    { 1, true },
    { 2, 1 },
    { 3, 1.2 },
    { "4", "hi" }
};

// Serialize
qDebug() << root_obj.toCbor().toHex();
qDebug() << QJsonDocument(root_obj.toJsonObject()).toJson().data();

// Parse
QCborValue cbor = QCborValue::fromCbor(data);
root_obj = cbor.toMap();

File System Operations

QDir

QDir dir;
qDebug() << QDir::current() << QDir::homePath();

// Directory operations
qDebug() << dir.mkdir("./hello") << dir.rmdir("hello");
dir.setFilter(QDir::Files);
dir.setNameFilters(QStringList("*.txt"));

// File information
QFileInfoList list = dir.entryInfoList();
for (auto&& i : list) {
    qDebug() << i.fileName() << i.size() << i.lastModified();
}

QFile

QFile f("./test.txt");
qDebug() << f.exists() << f.size();

// Write a file
if (f.open(QIODevice::WriteOnly | QIODevice::Text)) {
    QTextStream out(&f);
    out << "The magic number is: " << 49 << "\n";
    f.close();
}

// Read a file
if (f.open(QIODevice::ReadOnly | QIODevice::Text)) {
    QTextStream in(&f);
    while (!in.atEnd()) {
        QString line = in.readLine();
        qDebug() << line;
    }
    f.close();
}

QFileSystemWatcher

QFileSystemWatcher watcher(QStringList() << "/tmp" << "/tmp/test");

QObject::connect(&watcher, &QFileSystemWatcher::directoryChanged, [](const QString& path) {
    qDebug() << "dir" << path;
});
QObject::connect(&watcher, &QFileSystemWatcher::fileChanged, [](const QString& path) {
    qDebug() << "file" << path;
});

QSettings

QSettings is used to manage and save application settings.

QCoreApplication a(argc, argv);
a.setApplicationName("test");
a.setOrganizationName("iotworker");
a.setOrganizationDomain("test.com");

QSettings settings;

// Basic operations
settings.setValue("interval", 30);
qDebug() << settings.value("interval").toInt();

// Group operations
settings.beginGroup("group1");
settings.setValue("name", "Bob");
qDebug() << settings.value("name").toString();
settings.endGroup();

// Query and delete
qDebug() << settings.allKeys();
qDebug() << settings.contains("name");
settings.remove("group1/name");

Summary

Qt C++ provides a complete application development framework, from the basic object model to higher-level modules, covering most parts of modern application development. With this guide, you should now have a solid grasp of:

  • Qt development environment setup
  • The core object model and the signals-and-slots mechanism
  • Application infrastructure
  • Common modules and how to use them

Qt’s strength lies in its cross-platform capability and rich library set, which lets developers focus on business logic instead of platform differences. For C++ developers who need to build cross-platform applications, Qt is a framework worth learning.