Qt Development Fundamentals: Core Framework Concepts

Qt Creator Tool Overview and Usage

When creating a project using Qt, you're essentially establishing a window class where you can incorporate various components such as labels, buttons, and other UI elements. After project creation, several key files are generated:

File Purpose
widget.h Creates the window class where label classes, button classes, and other UI components can be added
widget.cpp Handles initialization of various classes including positioning, sizing, signals, and slot functions
main.cpp Entry point of the entire project, launches the application and calls other files to run the window program

First Qt Application Example

(1) Modify the "main.cpp" file.

#include "windowwidget.h"
#include <QApplication>

int main(int argc, char *argv[])
{
    QApplication app(argc, argv);
    WindowWidget win;                               // Create a window instance
    win.resize(600, 400);                         // Set window dimensions
    win.setWindowTitle("My First Qt Application"); // Configure window title
    win.show();
    return app.exec();
}

(2) Update the "windowwidget.h" file.

#ifndef WINDOWWIDGET_H
#define WINDOWWIDGET_H

#include <QWidget>
#include <QLabel>

class WindowWidget : public QWidget
{
    Q_OBJECT

public:
    WindowWidget(QWidget *parent = nullptr);
    ~WindowWidget();

private:
    // QLabel *labelDisplay = new QLabel("Qt Programming", this); // Avoid direct initialization in header
    QLabel *labelDisplay;
};
#endif // WINDOWWIDGET_H

(3) Adjust the "windowwidget.cpp" file.

#include "windowwidget.h"

WindowWidget::WindowWidget(QWidget *parent)
    : QWidget(parent)
{
    labelDisplay = new QLabel("Qt Programming", this);    // Initialize label in .cpp file
    labelDisplay->setGeometry(60, 60, 300, 120);         // Position and size the label
    labelDisplay->setStyleSheet("QLabel{background-color:blue;color:white}"); // Styling
    labelDisplay->setFont(QFont("Arial", 20));          // Font settings
}

WindowWidget::~WindowWidget()
{
}

(4) Execute the program.

Qt Signal-Slot Mechanism

Signal: Notification emitted under specific conditions.

Slot: Function that responds to signals.

The connection between signals and slots is implemented using the QObject::connect() function.

Signal-Slot Parameters

[static] QMetaObject::Connection QObject::connect(const QObject *emitter, const char *signal, const QObject *receiver, const char *method, Qt::ConnectionType type = Qt::AutoConnection)

| Parameter 1 (emitter) | Object emitting the signal | | Parameter 2 (signal) | Signal from the emitter object | | Parameter 3 (receiver) | Signal recipient | | Parameter 4 (method) | Slot function of receiver object, called when emitter's signal is detected |

Connection Patterns

(1) One signal connected to another signal:

connect(obj1, SIGNAL(signal1), obj2, SIGNAL(signal2));

(2) One signal connected to multiple slots:

connect(obj1, SIGNAL(signal1), obj2, SLOT(slot2));
connect(obj1, SIGNAL(signal1), obj3, SLOT(slot3));

(3) Multiple signals connected to the same slot:

connect(obj1, SIGNAL(signal1), obj2, SLOT(slot2));
connect(obj3, SIGNAL(signal3), obj2, SLOT(slot2));

(4) Standard connection pattern:

connect(obj1, SIGNAL(signal1), obj2, SLOT(slot2));

Signal-Slot Advantages

(1) Loose coupling: Signals and slots don't need to know who uses them or who they're used by, reducing coupling and making programs more stable.

(2) Type compatibility: Connection parameters must match. A class supporting signals and slots must inherit from QObject or its subclasses. Qt's signal-slot mechanism doesn't support templates.

Performance Considerations

While enhancing communication flexibility between objects, performance may be impacted. Calling a slot through signal emission runs slower than direct non-virtual function calls due to:

  • Signal queuing in multi-threaded environments
  • Parameter marshaling/unmarshaling
  • Safe traversal of all connections
  • Locating receiving objects

Sphere Volume Calculation Example

(1) Create a new project

(2) Modify "main.cpp" file.

#include "calcdialog.h"
#include <QApplication>

int main(int argc, char *argv[])
{
    QApplication app(argc, argv);
    CalcDialog dialog;
    dialog.setWindowTitle("Sphere Volume Calculator");
    dialog.show();
    return app.exec();
}

(3) Update "calcdialog.h" file.

#ifndef CALCDIALOG_H
#define CALCDIALOG_H

#include <QDialog>
#include <QLabel>
#include <QPushButton>
#include <QLineEdit>

class CalcDialog : public QDialog
{
    Q_OBJECT

public:
    CalcDialog(QWidget *parent = nullptr);
    ~CalcDialog();

private:
    QLabel *radiusLabel, *resultLabel;
    QLineEdit *radiusInput;
    QPushButton *calculateButton;

private slots:
    void calculateSphereVolume(); // Slot function for volume calculation
};
#endif // CALCDIALOG_H

(4) Modify "calcdialog.cpp" file.

#include "calcdialog.h"
#include <QGridLayout>

const static double PI_VALUE = 3.14159;

CalcDialog::CalcDialog(QWidget *parent)
    : QDialog(parent)
{
    radiusLabel = new QLabel(this);
    radiusLabel->setText(tr("Enter sphere radius:"));

    resultLabel = new QLabel(this);

    radiusInput = new QLineEdit(this);

    calculateButton = new QPushButton(this);
    calculateButton->setText(tr("Calculate Volume"));

    QGridLayout *layoutGrid = new QGridLayout(this);
    layoutGrid->addWidget(radiusLabel, 0, 0);
    layoutGrid->addWidget(radiusInput, 0, 1);
    layoutGrid->addWidget(resultLabel, 1, 0);
    layoutGrid->addWidget(calculateButton, 1, 1);

    connect(calculateButton, SIGNAL(clicked()), this, SLOT(calculateSphereVolume()));
}

CalcDialog::~CalcDialog()
{
}

void CalcDialog::calculateSphereVolume()
{
    bool conversionSuccess;
    QString displayText;
    QString inputRadius = radiusInput->text();
    int radiusValue = inputRadius.toInt(&conversionSuccess);
    double volumeResult = 4.0/3.0 * PI_VALUE * radiusValue * radiusValue * radiusValue;
    resultLabel->setText(displayText.setNum(volumeResult));
}

String Classes and Common Data Types

Qt String Operations

Create a Qt Console Application.

String Concatenation with "+"

#include <QCoreApplication>
#include <QDebug>

int main(int argc, char *argv[])
{
    QCoreApplication app(argc, argv);
    
    QString firstStr = "Welcome to ";
    firstStr = firstStr + "Qt Development";
    qDebug() << firstStr;
    qDebug() << qPrintable(firstStr);

    QString secondStr = "54321";
    secondStr += "VWXYZ";
    qDebug() << secondStr;
    return app.exec();
}

Using "QString::append" for Concatenation

#include <QCoreApplication>
#include <QDebug>

int main(int argc, char *argv[])
{
    QCoreApplication app(argc, argv);

    QString greeting = "Good";
    QString farewell = "morning";
    greeting.append(farewell);
    qDebug() << qPrintable(greeting);
    greeting.append("Hello Universe!");
    qDebug() << qPrintable(greeting);
    return app.exec();
}

"QString::asprintf()" String Formatting

For C++17:

#include <QCoreApplication>
#include <QDebug>

int main(int argc, char *argv[])
{
    QCoreApplication app(argc, argv);

    QString tempString;
    tempString = QString::asprintf("%s", "Greeting ");
    qDebug() << qPrintable(tempString);
    tempString = QString::asprintf("%s", "Greeting Universe!");
    qDebug() << qPrintable(tempString);
    tempString = QString::asprintf("%s %s", "Welcome", "here.");
    qDebug() << qPrintable(tempString);
}

For C++11:

#include <QCoreApplication>
#include <QDebug>

int main(int argc, char *argv[])
{
    QCoreApplication app(argc, argv);

    QString tempString;
    tempString.sprintf("%s", "Greeting ");
    qDebug() << qPrintable(tempString);
    tempString.sprintf("%s", "Greeting Universe!");
    qDebug() << qPrintable(tempString);
    tempString.sprintf("%s %s", "Welcome", "here.");
    qDebug() << qPrintable(tempString);
    return app.exec();
}

"QString::arg()" String Formatting

#include <QCoreApplication>
#include <QDebug>

int main(int argc, char *argv[])
{
    QCoreApplication app(argc, argv);

    QString tempString;
    tempString = QString("%1 was born in %2.").arg("Alice").arg(2001);
    qDebug() << tempString;
    return app.exec();
}

"QString::insert()" Function

Inserts text at a specified position.

#include <QCoreApplication>
#include <QDebug>

int main(int argc, char *argv[])
{
    QCoreApplication app(argc, argv);

    QString digit = "five";
    QString memory = "Memory is ten seconds story";
    memory.insert(7, digit);
    qDebug() << memory;
    // Result: Memory is five ten seconds story
    return app.exec();
}

"QString::prepend()" Function

Prepends text to the beginning of the source string.

#include <QCoreApplication>
#include <QDebug>

int main(int argc, char *argv[])
{
    QCoreApplication app(argc, argv);

    QString subject = "Cat";
    QString story = " has a ten minute memory";
    story.prepend(subject);
    qDebug() << story;
    return app.exec();
}

"QString::replace()" Function

Replaces specified content in the source string.

#include <QCoreApplication>
#include <QDebug>

int main(int argc, char *argv[])
{
    QCoreApplication app(argc, argv);

    QString memory = "Cat has a ten minute memory";
    memory.replace("ten", "twenty");
    qDebug() << memory;
    return app.exec();
}

"QString::startsWith()" Function

Checks if a string begins with a specific substring.

Qt::CaseInsensitive means case-insensitive; Qt::CaseSensitive means case-sensitive; Counterpart: QString::endsWith().

#include <QCoreApplication>
#include <QDebug>

int main(int argc, char *argv[])
{
    QCoreApplication app(argc, argv);

    QString testString = "What is your name?";
    qDebug() << testString.startsWith("What", Qt::CaseSensitive);     // true
    qDebug() << testString.startsWith("whAT", Qt::CaseSensitive);    // false
    qDebug() << testString.startsWith("whAT", Qt::CaseInsensitive);  // true
    qDebug() << testString.startsWith("name", Qt::CaseSensitive);    // false
    return app.exec();
}

"QString::contains()" Function

Checks if a specified substring exists within a string.

#include <QCoreApplication>
#include <QDebug>

int main(int argc, char *argv[])
{
    QCoreApplication app(argc, argv);
    
    QString testString = "What is your name?";
    qDebug() << testString.contains("your", Qt::CaseSensitive);      // true
    qDebug() << testString.contains("what", Qt::CaseInsensitive);    // false
    return app.exec();
}

"QString::toInt()" Function

Similar functions exist: "QString::toDouble()" function "QString::toFloat()" function "QString::toLong()" function

#include <QCoreApplication>
#include <QDebug>

int main(int argc, char *argv[])
{
    QCoreApplication app(argc, argv);

    QString numberStr = "42";
    bool success;
    int hexValue = numberStr.toInt(&success, 16);
    qDebug() << "success=" << success << "," << "hex=" << hexValue << Qt::endl;
    return app.exec();
}

"QString::compare()" Function

#include <QCoreApplication>
#include <QDebug>
#include <iostream>
using namespace std;

int main(int argc, char *argv[])
{
    QCoreApplication app(argc, argv);

    int comparison1 = QString::compare("hello", "HELLO", Qt::CaseInsensitive);
    int comparison2 = QString::compare("about", "Dog", Qt::CaseSensitive);
    int comparison3 = QString::compare("hello", "Dog", Qt::CaseInsensitive);
    cout << "comparison1=" << comparison1 << "," << "comparison2=" << comparison2 << "," << "comparison3=" << comparison3 << endl;
    return app.exec();
}

Converting QString to ASCII Codes

#include <QCoreApplication>
#include <QDebug>
#include <iostream>
using namespace std;

int main(int argc, char *argv[])
{
    QCoreApplication app(argc, argv);    
    QString text = "XYZ xyz";
    QByteArray byteData = text.toUtf8();
    for (int i = 0; i < text.size(); i++)
        qDebug() << int(byteData.at(i));

    return app.exec();
}

Common Qt Basic Data Types (defined in #include<QtGlobal>)

Data Types

Type Name Description Notes
qint8 signed char 8-bit signed integer
qint16 signed short 16-bit signed integer
qint32 signedd int 32-bit signed integer
qint64 long long int or (_int64) 64-bit signed integer, defined as _int64 on Windows
qintptr qint32 or qint64 Pointer type varies by system, qint32 on 32-bit, qint64 on 64-bit
qlonglong long long int or (_int64) Defined as _int64 on Windows
qptrdiff qint32 or qint64 Varies by system, qint32 on 32-bit, qint64 on 64-bit
qreal double or float Defaults to double unless configured with -qreal float
quint8 unsigned char 8-bit unsigned integer
quint16 unsigned shortt 16-bit unsigned integer
quint32 unsigned int 32-bit unsigned integer
quint64 unsigned long long int or (unsigned _int64) 64-bit unsigned integer, defined as unsigned_int64 on Windows
quintptr quint32 or quint64 Varies by system, quint32 on 32-bit, quint64 on 64-bit
qulonglong unsigned long long int or (unsigned _int64) Defined as _int64 on Windows
uchar unsigned char Unsigned character type
uint unsigned int Unsigned integer
ulong unsigned long Unsigned long integer
ushort unsigned short Unsigned short integer

QDateTime & QByteArray

#include <QCoreApplication>
#include <QDebug>
#include <iostream>
#include <QDateTime>
using namespace std;

int main(int argc, char *argv[])
{
    QDateTime dateTime;
    QString dateString = dateTime.currentDateTime().toString("yyyy-MM-dd hh:mm:ss");
    qDebug() << dateString << Qt::endl;
    
    QByteArray original("Qt Development Sample Text.");
    QByteArray lowercase = original.toLower();
    qDebug() << lowercase << Qt::endl;
    QByteArray uppercase = original.toUpper();
    qDebug() << uppercase << Qt::endl;
    return app.exec();
}

QMap, QHash, QVector

QMap Class

QMap<Key,T> provides a mapping from keys of type Key to values of type T. Typically, QMap stores data as one key per value, storing data in key order. For one-key-multiple-values scenarios, QMap provides QMap<Key,T>::insertMulti() and QMap<Key,T>::values() functions. QMultiMap class instantiates a QMap object.

#include <QCoreApplication>
#include <QDebug>

int main(int argc, char *argv[])
{
    QCoreApplication app(argc, argv);

    // QMap example
    QMap<QString, int> mapExample;
    mapExample["Literature"] = 115;
    mapExample["History"] = 125;

    mapExample.insert("Geography", 110);
    mapExample.insert("Biology", 95);
    mapExample.insert("Art", 105);
    qDebug() << mapExample << Qt::endl;

    mapExample.remove("Art");
    qDebug() << mapExample << Qt::endl;

    // Iterating through QMap
    QMapIterator<QString, int> iterator(mapExample);
    while(iterator.hasNext())
    {
        iterator.next();
        qDebug() << iterator.key() << ":" << iterator.value();
    }

    // STL-style iteration
    QMap<QString, int>::const_iterator stlIter = mapExample.constBegin();
    while(stlIter != mapExample.constEnd())
    {
        qDebug() << stlIter.key() << ":" << stlIter.value();
        stlIter++;
    }

    // Lookup operations
    qDebug() << Qt::endl;
    qDebug() << "key-->value:" << mapExample.value("Geography");
    qDebug() << "value-->key:" << mapExample.key(95) << Qt::endl;

    // Update value
    mapExample.insert("Geography", 118);
    qDebug() << mapExample.value("Geography");

    // Check existence
    qDebug() << "result=" << mapExample.contains("Literature");
    qDebug() << "result=" << mapExample.contains("Art");

    // Get all keys and values
    qDebug() << Qt::endl;
    QList<QString> keys = mapExample.keys();
    qDebug() << keys;
    QList<int> values = mapExample.values();
    qDebug() << values;
    
    // One key to multiple values
    QMultiMap<QString, QString> multiMap;
    multiMap.insert("student", "id");
    multiMap.insert("student", "name");
    multiMap.insert("student", "gender");
    multiMap.insert("student", "age");
    multiMap.insert("student", "height");
    multiMap.insert("student", "weight");
    qDebug() << multiMap;
    return app.exec();
}

QHash Class

QHash<Key,T> has nearly identical API to QMap. QHash maintains a hash table that adapts to the number of items.

QHash organizes data in arbitrary order. When storage order doesn't matter, QHash is recommended for data containers.

Differences between QMap and QHash:

(1) QHash and QMap have similar functionality, but QHash offers faster lookup speeds; (2) QMap stores data in key order, while QHash stores in arbitrary order; (3) QMap keys must provide "<" operator, while QHash keys must provide "==" operator and a global qHash() function.

#include <QCoreApplication>
#include <QDebug>

int main(int argc, char *argv[])
{
    QCoreApplication app(argc, argv);

    // QHash example
    QHash<QString, int> hashExample;
    hashExample["item 1"] = 5;
    hashExample["item 1"] = 10;
    hashExample["item 4"] = 6;
    hashExample["item 2"] = 4;
    hashExample.insert("item 3", 40);

    QList<QString> keyList = hashExample.keys();
    for(int i = 0; i < keyList.length(); i++)
        qDebug() << keyList[i] << "," << hashExample.value(keyList[i]);

    // QHash iterator
    qDebug() << Qt::endl;
    QHash<QString, int> hashContainer;
    hashContainer["item 1"] = 35;
    hashContainer["item 2"] = 45;
    hashContainer["item 3"] = 55;
    hashContainer["item 4"] = 65;
    hashContainer.insert("item 3", 110);

    QHash<QString, int>::const_iterator hashIter;
    for(hashIter = hashContainer.begin(); hashIter != hashContainer.end(); hashIter++)
        qDebug() << hashIter.key() << "-->" << hashIter.value();

    // Existence check
    qDebug() << "result=" << hashContainer.contains("item 4");
    // Remove item
    hashContainer.remove("item 4");
    for(hashIter = hashContainer.begin(); hashIter != hashContainer.end(); hashIter++)
        qDebug() << hashIter.key() << "-->" << hashIter.value();

    return app.exec();
}

QVector Class

QVector<T> stores a sequence of values of type T in adjacent memory locations. Insertion operations at the front or middle of a QVector are slow because they require moving large amounts of data due to how QVector stores data.

#include <QCoreApplication>
#include <QDebug>

int main(int argc, char *argv[])
{
    QCoreApplication app(argc, argv);

    // QVector example
    QVector<int> vectorExample;
    // First assignment method
    vectorExample << 15;
    vectorExample << 25;
    vectorExample << 35;
    vectorExample << 45;
    // Second assignment method
    vectorExample.append(55);
    vectorExample.append(65);
    vectorExample.append(75);
    vectorExample.append(85);
    vectorExample.append(105);
    vectorExample.append(95);
    qDebug() << vectorExample << Qt::endl;

    // Count elements
    qDebug() << "vector count=" << vectorExample.count() << Qt::endl;

    // Iterate through elements
    for(int i = 0; i < vectorExample.count(); i++)
        qDebug() << vectorExample[i];

    // Remove elements
    qDebug() << Qt::endl;
    vectorExample.remove(0);          // Remove first element
    for(int i = 0; i < vectorExample.count(); i++)
        qDebug() << vectorExample[i];

    qDebug() << Qt::endl;
    vectorExample.remove(2, 3);       // Remove 3 elements starting from index 2
    for(int i = 0; i < vectorExample.count(); i++)
        qDebug() << vectorExample[i];

    // Check containment
    qDebug() << Qt::endl;
    qDebug() << "result:" << vectorExample.contains(95) << Qt::endl;
    qDebug() << "result:" << vectorExample.contains(650) << Qt::endl;
    return app.exec();
}

QList Class & QLinkedList Class

QList Class

QList<T> employs different storage strategies based on data types:

(1) If T is a pointer type or basic type with pointer-size bytes, QList<T> stores values directly in its array.

(2) If QList<T> stores pointers to objects, the pointers reference the actual objects.

#include <QCoreApplication>
#include <QDebug>

int main(int argc, char *argv[])
{
    QCoreApplication app(argc, argv);

    // QList example
    QList<int> listExample;   // Initialize empty QList<int>
    for(int i = 0; i < 10; i++)
        listExample.insert(listExample.end(), i + 15);
    qDebug() << listExample;

    // Read-write iterator
    QList<int>::iterator iter;
    qDebug() << Qt::endl;
    qDebug() << "Result1:";
    for(iter = listExample.begin(); iter != listExample.end(); iter++)
    {
        qDebug() << (*iter);
        *iter = (*iter) * 10 + 8;
    }

    // Read-only iterator
    qDebug() << Qt::endl;
    qDebug() << "Result1:";
    QList<int>::const_iterator constIter;
    for(constIter = listExample.constBegin(); constIter != listExample.constEnd(); constIter++)
        qDebug() << *constIter;

    // Add elements
    listExample.append(777);
    QList<int>::iterator iter1;
    qDebug() << Qt::endl;
    qDebug() << "Result2:";
    for(iter1 = listExample.begin(); iter1 != listExample.end(); iter1++)
        qDebug() << *iter1;

    // Find elements
    qDebug() << Qt::endl;
    qDebug() << "Result3:";
    qDebug() << listExample.at(3);
    qDebug() << listExample.contains(88);
    qDebug() << listExample.contains(188);

    // Modify elements
    qDebug() << Qt::endl;
    qDebug() << "Result4:";
    listExample.replace(5, 999);
    qDebug() << listExample;

    // Remove elements
    qDebug() << Qt::endl;
    qDebug() << "Result5:";
    listExample.removeAt(0);
    listExample.removeFirst();
    listExample.removeAt(6);
    qDebug() << listExample;

    return app.exec();
}

QLinkedList Class

In Qt6, QLinkedList class usage workaround:

QLinkedList<T> is a linked list that stores data in non-contiguous memory blocks. QLinkedList<T> cannot use indexing, only iterators for data access. Compared to QList, QLinkedList offers higher efficiency when inserting into large lists.

QLinkedList class cannot access elements by index. For large-scale data storage, QLinkedList is recommended (fast, efficient insertion and deletion).

#include <QCoreApplication>
#include <QDebug>
#include <QLinkedList>

int main(int argc, char *argv[])
{
    QCoreApplication app(argc, argv);

    // QLinkedList example
    QLinkedList<QString> monthList;
    for(int i = 1; i <= 12; i++)
        monthList << QString("%1%2").arg("Month: ").arg(i);

    // Read-write iterator
    qDebug() << "Result1:";
    QLinkedList<QString>::iterator writeIter = monthList.begin();
    for(; writeIter != monthList.end(); writeIter++)
        qDebug() << *writeIter;

    // Read-only iterator
    qDebug() << Qt::endl << "Result2:";
    QLinkedList<QString>::const_iterator readIter = monthList.constBegin();
    for(; readIter != monthList.end(); readIter++)
        qDebug() << *readIter;
    return app.exec();
}

STL-Style Iterator Container Traversal

Container Class Read-Only Iterator Read-Write Iterator
QList<T>, QQueue<T> QList<T>::const_iterator QList<T>::iterator
QLinkedList<T> QLinkedList<T>::const_iterator QLinkedList<T>::iterator

QVariant Class Applications

QVariant class is essentially a C++ union data type that can store many Qt type values, including QBrush, QColor, QString, etc. It can also store Qt container type values.

QVariant::StringList is an enum variable defined by Qt for QVariant::type. Other common enum variables include:

Variable Corresponding Type Variable Corresponding Type
QVariant::Invalid Invalid type QVariant::Time QTime
QVariant::Region QRegion QVariant::Line QLine
QVariant::Bitmap QBitmap QVariant::Palette QPalette
QVariant::Bool bool QVariant::List QList
QVariant::Brush QBrush QVariant::SizePolicy QSizePolicy
QVariant::Size QSize QVariant::String QString
QVariant::Char QChar QVariant::Map QMap
QVariant::Color QColor QVariant::StringList QStringList
QVariant::Cursor QCursor QVariant::Point QPoint
QVariant::Date QDate QVariant::Pen QPen
QVariant::DateTime QDateTime QVariant::Pixmap QPixmap
QVariant::Double double QVariant::Rect QRect
QVariant::Font QFont QVariant::Image QImage
QVariant::Icon QIcon QVariant::UserType User-defined type

Example:

(1) Create MainWindow project;

(2) Modify "main.cpp" file;

#include "mainwindow.h"
#include <QApplication>

int main(int argc, char *argv[])
{
    QApplication app(argc, argv);
    MainWindow window;
    return app.exec();
}

(3) Modify "mainwindow.h" file;

#ifndef MAINWINDOW_H
#define MAINWINDOW_H

#include <QMainWindow>

// Define student structure
struct Student
{
    int id;
    QString name;
    int grade;
};
Q_DECLARE_METATYPE(Student)

class MainWindow : public QMainWindow
{
    Q_OBJECT

public:
    MainWindow(QWidget *parent = nullptr);
    ~MainWindow();
};
#endif // MAINWINDOW_H

(4) Modify "mainwindow.cpp" file

#include "mainwindow.h"
#include <QVariant>
#include <QDebug>
#include <QColor>

MainWindow::MainWindow(QWidget *parent)
    : QMainWindow(parent)
{
    QVariant var1(398);
    qDebug() << "var1:" << var1.toInt();

    QVariant var2("shanghai");
    qDebug() << "var2:" << var2.toString();

    QMap<QString, QVariant> mapExample;
    qDebug() << Qt::endl;
    mapExample["integer"] = 3000;
    mapExample["decimal"] = 109.98;
    mapExample["text"] = "excellent";
    mapExample["color"] = QColor(255, 0, 255);    // QColor type

    // Output and conversion
    qDebug() << mapExample["integer"] << mapExample["integer"].toInt();
    qDebug() << mapExample["decimal"] << mapExample["decimal"].toDouble();
    qDebug() << mapExample["text"] << mapExample["text"].toString();
    qDebug() << mapExample["color"] << mapExample["color"].value<QColor>();

    // Create string list: QStringList
    qDebug() << Qt::endl;
    QStringList stringList;
    stringList << "X" << "Y" << "Z" << "W" << "V" << "U";

    QVariant listVar(stringList);   // Store list in QVariant variable
    if(listVar.type() == QVariant::StringList)
    {
        QStringList retrievedList = listVar.toStringList();
        for(int i = 0; i < retrievedList.size(); i++)
        {
            qDebug() << retrievedList.at(i);          // Output list data
        }
    }

    // Structure and QVariant combination
    qDebug() << Qt::endl;
    Student studentInfo;
    studentInfo.id = 202408;
    studentInfo.name = "alice";
    studentInfo.grade = 825;

    // Use static method for storage
    QVariant studentVar = QVariant::fromValue(studentInfo);
    if(studentVar.canConvert<Student>())              // Check convertibility
    {
        Student temp = studentVar.value<Student>();     // Retrieve data
        Student converted = qvariant_cast<Student>(studentVar);     // Retrieve data alternative

        qDebug() << "student:id=" << temp.id << ",name=" << temp.name << ",grade=" << temp.grade;
        qDebug() << "student:id=" << converted.id << ",name=" << converted.name << ",grade=" << converted.grade;
    }
}

MainWindow::~MainWindow()
{
}

Common Algorithms and Regular Expressions

Common Algorithms

(1) double c = qAbs(a): qAbs() returns absolute value of double a; (2) double max = qMax(b,c): qMax() returns maximum of two values; (3) int bn = qRound(b): Returns closest integer to floating-point number (rounding); (4) int cn = qSwap(bn,cn): Swaps values of two numbers;

Example:

(1) Create widget project;

(2) Modify "widget.cpp" file;

#include "widget.h"
#include <QtGlobal>

Widget::Widget(QWidget *parent)
    : QWidget(parent)
{
    double num1 = -88.754, num2 = 35.88;
    double absResult = qAbs(num1);        // Absolute value
    qDebug() << "num1=" << absResult;

    double maxResult = qMax(num1, num2);     // Maximum value
    qDebug() << "maxResult" << maxResult;

    int rounded1 = qRound(num2);          // Rounding
    qDebug() << "rounded1=" << rounded1;
    int rounded2 = qRound(num1);          // Rounding
    qDebug() << "rounded2=" << rounded2;

    qSwap(num1, num2);              // Swap values
    qDebug() << num1 << "," << num2 << Qt::endl;
}

Widget::~Widget()
{
}

Regular Expressions

Regular expressions, also known as pattern expressions (Regular Expression, abbreviated as regex, regexp, or RE in code), are text patterns containing ordinary characters (such as letters from a to z) and special characters (called "metacharacters"). Regular expressions use single strings to describe, match sequences of strings that follow certain grammatical rules, typically used for searching and replacing text that matches specific patterns. Regular expressions describe string matching patterns that can check if a string contains certain substrings, replace matched substrings, or extract substrings meeting specific criteria.

Regular expressions consist of expressions, quantifiers, and assertions.

(1) The simplest expression is a character. Character sets can use expressions like "[AEIOU]", matching all uppercase vowels; using "[^AEIOU]" matches all non-vowel letters, i.e., consonants; consecutive character sets can use expressions like "[a-z]", matching all lowercase English letters.

(2) Quantifiers specify occurrence counts of expresions, such as "x[1,2]" meaning "x" can appear at least once, at most twice.

Quantifiers in Regular Expressions:

Quantifier Meaning Quantifier Meaning
E? Matches 0 or 1 time E{n,} Matches at least n times
E+ Matches 1 or more times E{,m} Matches at most m times
E* Matches 0 or more times E{n,m} Matches at least n, at most m times
E{n} Matches n times

Assertions in Regular Expressions:

Symbol Meaning Symbol Meaning
^ Matches at string start \B Non-word boundary
$ Matches at string end (?=E) Matches only if followed by E
\b Word boundary (?!E) Matches only if not followed by E

Example:

(1) Create mainwindow project;

(2) Modify "mainwindow.cpp" file;

#include "mainwindow.h"
#include <QDebug>
#include <regex>
#include <QString>

MainWindow::MainWindow(QWidget *parent)
    : QMainWindow(parent)
{
    /*
     * Match phone numbers via regular expression
     * 11 digits with different encoding patterns
     * First 3: Network identification (China Mobile, China Unicom, China Telecom)
     * Last 8-11: User numbers
     * China Mobile: 134 159 158 188
     * China Unicom: 130 133 189 156
     * Pattern: starts with 1, second digit 3 5 8, total 11 digits
     */

    QString phoneNumber = "18865475968";
    std::regex pattern("^1(3|5|8)\\d{9}$");
    std::string phoneString = phoneNumber.toStdString();

    qDebug() << "Phone Number:" << phoneNumber;

    // Perform matching
    bool matchResult = std::regex_match(phoneString, pattern);
    if(!matchResult)
    {
        qDebug() << "PhoneNumber" << "-->Invalid phone number.";
    }
    else
    {
        qDebug() << phoneNumber << "-->Valid phone number.";
    }
}

MainWindow::~MainWindow()
{
}

Tags: Qt development Qt framework Qt signals and slots Qt string handling Qt containers

Posted on Tue, 30 Jun 2026 16:20:57 +0000 by jamesgrayking