Skip to content

Qt

Tremendous Speed-Up with SQL Transactions

The function CustomerDatabase::importCustomers reads 500 customers from the list c_customers, creates an SQL query cmd for each customer and inserts each customer into the Customers table of the SQL database db.

void CustomerDatabase::importCustomers() {
    auto db = QSqlDatabase::database("CustomerDB");
    for (auto row : c_customers) {
        auto cmd = QString{"INSERT INTO Customers "
                   "(fullName, street, postalCode, city, phone, email) "
                   "VALUES (\'%1\')"}.arg(row.join("\', \'"));
        auto query = QSqlQuery{cmd, db};
    }
}

On an NXP i.MX6 SoC with four Cortex-A9 cores, this function takes 17.5 seconds! Your user would have to wait more than 17.5 seconds for the import of a CSV file with 500 customers to finish. This is unacceptable. How can you speed up the import to 0.2 seconds?
Read More »Tremendous Speed-Up with SQL Transactions

Monitoring Sys Files with QFileSystemWatcher

When the driver turns off the ignition in a vehicle, display computers like terminals in harvesters or infotainment systems in cars should be notified. The display computers should save important data and shut down orderly.

When the display computer runs on Linux, it learns the status of the ignition by monitoring the GPIO for clamp 15. Linux writes the value of the GPIO to a special file in the sys filesystem. On one of my display computers, clamp15 is mapped to the special file /sys/class/gpio/gpio72/value. When the ignition is on, this file contains the string “1”. When off, this file contains “0”. The number of GPIO (here: 72) varies from display computer to display computer.

On the Linux command line, we get the value of clamp 15 with this command:

$ cat /sys/class/gpio/gpio72/value
1

The command returns “0” when the ignition is off and “1” when it is on.

How can a Qt application monitor the status of the GPIO clamp 15 such that it can shut down orderly when the driver turns off the ignition?
Read More »Monitoring Sys Files with QFileSystemWatcher

QML Engine Deletes C++ Objects Still In Use

Correction: In the original post, I stated that ownership is transferred from C++ to QML by READ functions of Q_PROPERTYs. This is wrong. Ownership is only transferred by Q_INVOKABLE functions and slots, which return a QObject pointer. I corrected my post and my code example. Now, the simple code example crashes as desired. Many thanks to Richard and Simon for pointing out my mistake.

I recently spent three days on a customer project to figure out why my QML application crashed with a segmentation fault. The crash happened after a long sequence of interactions, which was hard to reproduce. I finally managed to reproduce the crash reliably after going through the same six-step interaction four times.

After many hours of debugging and scrutinising my code, I had an epiphany about the stack trace leading to the crash. The stack trace originated from deep inside the QML engine and ended in calling the destructor of a C++ object, which was still in use on the C++ side. The trace never touched any of the application’s C++ code in between.

So far, I had only asked myself the question: Where in my C++ code do I corrupt the memory? After my little epiphany, I changed my question: Why does the QML engine delete a C++ object still in use? What do I overlook in the interaction between QML and C++?
Read More »QML Engine Deletes C++ Objects Still In Use

Converting a QByteArray into an Unsigned Integer

My program received messages from a network as an array of bytes. The sender of the messages encoded integers in Big Endian format. So, the hex number 0x1540 arrived in the sequence [0x15, 0x40]. I wrote the following function, which converts such a byte array of at most four bytes into a 32-bit unsigned integer. The function converts the sequence [0x15, 0x40] into the hex number 0x1540.

quint32 byteArrayToUint32(const QByteArray &bytes)
{
    auto count = bytes.size();
    if (count == 0 || count > 4) {
        return 0;
    }
    quint32 number = 0U;
    for (int i = 0; i < count; ++i) {
        auto b = static_cast<quint32>(bytes[count - 1 - i]);
        number += static_cast<quint32>(b << (8 * i));
    }
    return number;
}

Of course, I also wrote a unit test.

void TestByteArrayToUint32::testByteArrayToUint32()
{
    QCOMPARE(byteArrayToUint32(QByteArray::fromHex("9020562f")), 0x9020562fU);
    QCOMPARE(byteArrayToUint32(QByteArray::fromHex("314922")), 0x314922U);
    QCOMPARE(byteArrayToUint32(QByteArray::fromHex("1540")), 0x1540U);
    QCOMPARE(byteArrayToUint32(QByteArray::fromHex("38")), 0x38U);
    QCOMPARE(byteArrayToUint32(QByteArray::fromHex("")), 0x0U);
    QCOMPARE(byteArrayToUint32(QByteArray::fromHex("559020562f")), 0x0U);
}

All QCOMPARE checks passed. All seemed fine. After using my function for a (short) while, a test didn't want to pass. I tracked the problem down to my function. Converting the byte array [0x01, 0x80] yielded the result 0x80.

Can you spot the bug in my code - and in my test?
Read More »Converting a QByteArray into an Unsigned Integer

New in Qt 5.10: Dynamic Language Change in QML

My favourite new feature in Qt 5.10 is the inconspicuous function QmlEngine::retranslate(). Finally, seven years after QML’s birth, there is a Qt way to change the language of your application at runtime. There is no need for workarounds any more (see How to do dynamic translation in QML for the standard workaround).

I wrote a simple application demonstrating the new feature. If we click the British (German) flag on the right-hand side, the language of the labels on the left-hand side is changed accordingly.

How does the dynamic language change work?
Read More »New in Qt 5.10: Dynamic Language Change in QML

Pretty-Printing Output for QCOMPARE

We have created a custom class, say Person, and use it in a unit test.

void TestPerson::testEquality()
{
    Person p1("Alice", 42);
    Person p2("Bob", 37);
    QCOMPARE(p1, p2);
}

The unit test fails with this message.

FAIL!  : TestPerson::testEquality() Compared values are not the same
   Loc: [../QComparePrint/TestPerson.cpp(8)]

This message does not tell us how the two Person objects differ. We would like to see this message as we would see it for any type known to QCOMPARE.

FAIL!  : TestPerson::testEquality() Compared values are not the same
   Actual   (p1): "Person(Alice, 42)"
   Expected (p2): "Person(Bob, 37)"
   Loc: [../QComparePrint/TestPerson.cpp(16)]

How do we achieve such a pretty-printed output for QCOMPARE?
Read More »Pretty-Printing Output for QCOMPARE

Passing Enum Properties between C++ and QML

We have defined a Qt property warningLevel in the C++ class MainModel:

    Q_PROPERTY(WarningLevel::Enum warningLevel READ warningLevel
               WRITE setWarningLevel NOTIFY warningLevelChanged)

We want to use this property in QML. For example, we want to colour a rectangle according to the warningLevel:

    import com.embeddeduse.models 1.0
    // ...

    property MainModel mainModel : MainModel {}

    Rectangle {
        color: toColor(mainModel.warningLevel)
        // ...
    }

    function toColor(level) {
        switch (level) {
        case WarningLevel.Error:
            return "red"
        case WarningLevel.Warning:
            return "orange"
        case WarningLevel.Info:
            return "green"
        case WarningLevel.Debug:
            return "purple"
        default:
            return "magenta"
        }
    }

Note how we access the C++ property mainModel.warningLevel from QML to set the color of the rectangle and how we use symbolic enum constants like WarningLevel.Info in the function toColor().

It is similarly easy to use a list of the symbolic enum constants as the model of a Repeater and to assign the warning level by the user to the property mainModel.warningLevel in the onReleased handler of a MouseArea.

    Repeater {
        model: [WarningLevel.Error, WarningLevel.Warning, WarningLevel.Info,
            WarningLevel.Debug]
        Rectangle {
            color: toColor(modelData)
            // ...
            MouseArea {
                anchors.fill: parent
                onReleased: mainModel.warningLevel = modelData
            }
        }
    }

I’ll show you in the rest of this post how to write your C++ code so that you can use a C++ property of enum type easily in QML.
Read More »Passing Enum Properties between C++ and QML