> ## Content Index
> Fetch the complete content index at: https://www.smallstepsystems.com/llms.txt
> Use this file to discover other available public pages before exploring further.

# Migrating a Harvester HMI from Qt 5.12 to Qt 6.2
- URL: https://www.smallstepsystems.com/migrating-a-harvester-hmi-from-qt-5-12-to-qt-6-0/
- Published: 2021-01-17T13:39:39.000Z
- Updated: 2026-01-25T12:28:31.000Z
- Author: Burkhard Stubert

September 2021 saw the [launch of Qt 6.2](https://www.qt.io/blog/qt-6.2-lts-released?ref=smallstepsystems.com) \- the first Qt 6 version with feature parity to Qt 5.15\. I wanted to find out whether Qt 6.2 is fit for products. So, I migrated the HMI application of the [ROPA sugar beet harvesters](https://www.smallstepsystems.com/qt-controller-area-networks-talk-qtws19/) from Qt 5.12 over Qt 5.15 to Qt 6.2\. The migration went very smooth and quick. And yes, Qt 6.2 is fit for products!

## Introduction

The migration to Qt 6 is my 5th Qt migration. The migrations from Qt 1 to Qt 2, from Qt 2 to Qt 3 and from Qt 4 to Qt 5 were fairly smooth. The migration of an IDE for formal verification and of the driver terminal of a forage harvester were a matter of 2-3 days. The migration from Qt 3 to Qt 4 was extremely painful. Migrating an IDE for Bluetooth development took me 6 months.

I was curious how long I would need to migrate the driver terminal of a [sugar beet harvester](https://www.smallstepsystems.com/qt-controller-area-networks-talk-qtws19/) from Qt 5.12 to Qt 6.2\. The driver terminal has 350 source files (.cpp, .h, .qml) with 50K lines of hand-written code. It also has 45 source files with 74K lines of generated code for the terminal-machine communication.

The guide [Porting to Qt 6](https://doc.qt.io/qt-6/portingguide.html?ref=smallstepsystems.com) from the official Qt documentation is the starting point for the migration. It suggests to port the application to Qt 5.15 in a first step and to Qt 6.2 in a second step. The Qt developers made the APIs of Qt 5.15 as similar as possible to the APIs of Qt 6.2 to reduce the migration efforts.

I'll describe step by step how to change the CMake files, how to fix the warnings and errors flagged by the C++ compiler, how to find the QML incompatibilities and how to set up the development environment for Qt 6.2.

Originally, I migrated the terminal application to Qt 6.0 in December 2020 - just after Qt 6.0 came out. Qt 6.0 and Qt 6.1 were not ready for product releases, because they lacked important modules like SerialBus, Multimedia, Charts, RemoteObjects and WebEngine. I had to to exclude some parts from the migration.

The Qt Project promised to fix these shortcomings with Qt 6.2 in autumn 2021 and they delivered. Excellent work! I decided to update my original post as well. The post now covers the migration from Qt 5.12 all the way to Qt 6.2\. With Qt 6.2, I could include SerialBus and Multimedia. SerialBus with CAN worked right ouf the box. Multimedia required a straightforward rewrite for playing back MP3 files, because `QMediaPlaylist` was removed from Multimedia.

The migration of the harvester terminal from Qt 5.12 to Qt 6.2 took me two days. Writing this post took me longer. In October, I started to implement the driver terminal of a construction machine with Qt 6.2\. I use Qt 6.2 for my FOSS compliance checker. Hence, I can recommend the use of Qt 6 in products!

## Migrating from Qt 5.12 to Qt 5.15

The harvester application runs with Qt 5.12\. We install Qt 5.15.2 and QtCreator 4.13 on our development PC. The PC should run Ubuntu 16.04 or newer.

### C++ Compiler Warnings and Errors

The harvester application consists of three CMake projects: the executable `Main`, the library `Hmi` and the library `Can`. We switch on the deprecation warnings by adding the line

```
target_compile_definitions(${PROJECT_NAME} PUBLIC 
    "QT_DISABLE_DEPRECATED_BEFORE=0x050F00")
```

to the `CMakeLists.txt` of each project. This macro triggers a warning for every function that is deprecated in Qt 5.15 or older. Sometimes the use of a deprecated function causes an error. The next subsections list the C++ compiler warnings and errors I encountered while migrating the harvester application from Qt 5.12 to Qt 5.15.

The documentation page [Obsolete Classes](https://doc.qt.io/qt-5/obsoleteclasses.html?ref=smallstepsystems.com) lists all the classes that may be removed in future releases and all the classes with functions that may be removed in future releases. The documentation often gives a hint how to replace an obsolete class or function.

#### Error/Warning: 'endl' is deprecated: Use Qt::endl

*Problem*:

```
QTextStream os(&dbFile);
os << QStringLiteral("[access]") << endl;
```

Most occurrences of `endl` triggered the warning: `'endl' is deprecated: Use Qt::endl`. Some occurrences triggered an error: `‘endl’ was not declared in this scope`. The compiler couldn't distinguish between `std::endl` and `Qt::endl`.

*Fix*:

```
QTextStream os(&dbFile);
```

We replace each occurrence of `endl` by `Qt::endl`. All stream manipulators are now prefixed with the Qt namespace: for example, `Qt::hex`, `Qt::fixed`, `Qt::left` and `Qt::ws`.

#### Error: ‘longMonthName’ is not a member of ‘QDate’

*Problem*:

return QDate::longMonthName(i, **QDate::StandaloneFormat**);

The static function `QDate::longMonthName` was removed from `QDate`.

*Fix*:

return QLocale().monthName(i);

The documentation of `QDate::longMonthName` hints at `QLocale` for a replacement. `QLocale::monthName` returns the long month name by default.

#### Error: no matching function for call to ‘QProcess::execute(const char \[10\])’

*Problem*:

```
QProcess::execute("/bin/sync");
```

The variant of `QProcess::execute` with the command as its only argument was removed.

*Fix*:

```
QProcess::execute("/bin/sync", {});
```

We must always use the two-argument variant, where the second argument is a `QStringList` with the options and arguments of the command. As `sync` doesn't have any arguments or options, the second argument is the empty list.

#### Error: ‘mapped’ is not a member of ‘QSignalMapper’

***Problem***:

```
using MappedSignal = void(QSignalMapper::*)(int);
connect(&m_impl->m_signalMapper, 
        static_cast<MappedSignal>(&QSignalMapper::mapped),
        m_impl.data(),
        &DriverModel::Impl::onDriverChanged);
```

Before Qt 5.15, `QSignalMapper::mapped` had an overload for each of the four types of the single argument: `QObject*`, `QWidget*`, `const QString&` and `int`. We had to tell the compiler with a `static_cast` which overload to use in the connect statements. The overloads are obsolete in Qt 5.15.

*Fix*:

```
connect(&m_impl->m_signalMapper, &QSignalMapper::mappedInt,
        m_impl.data(), &DriverModel::Impl::onDriverChanged);
```

From Qt 5.15, the four overloads have different names `mappedInt`, `mappedObject`, `mappedString` and `mappedWidget`. This eliminates the cast and makes the code simpler.

#### Error: no member named 'insertMulti' in 'QMap >'

*Problem*:

```
QMap<int, std::function<void()>> importCalls;
importCalls.insertMulti(0, [this, path](
    {m_customerModel.importCsvFile(path);});
```

Before Qt 5.15, `QMap` distinguished between maps and multi-maps by `insert` and `insertMulti`.

*Fix*:

```
QMultiMap<int, std::function<void()>> importCalls;
importCalls.insert(0, [this, path](
    {m_customerModel.importCsvFile(path);});
```

Qt 5.15 introduces a new class `QMultiMap`, which inherits from `QMap`. We insert elements into a `QMultiMap` with `insert` now.

#### Error/Warning: ‘QString::SplitBehavior’ has not been declared

*Problem*:

```
auto nameParts = customer->name()
    .split(' ', QString::SkipEmptyParts);
```

Like many other enum constants, `QString::SkipEmptyParts` was moved into the namespace `Qt`. The problem often occurs as a warning:

```
‘... QString::split ...’ is deprecated: Use Qt::SplitBehavior variant instead [-Wdeprecated-declarations]
```

*Fix*:

```
auto nameParts = customer->name()
    .split(' ', Qt::SkipEmptyParts);
```

The warning tells us what to do. We replace `QString::SplitBehavior` by `Qt::SplitBehavior`.

#### Error: call of overloaded ‘append()’ is ambiguous

*Problem*:

```
QVector<QPair<QString, QString>> m_counterCats;
m_counterCats.append({"Gesamt", ""});
```

`QVector<T>::append` has gained a third overload for rvalue references `T&&` in addition to the existing `const T&` and `const QVector<T>&`. The C++17 compiler cannot distinguish between these three overloads.

*Fix*:

```
QVector<QPair<QString, QString>> m_counterCats;
m_counterCats.append(QPair<QString, QString>{"Gesamt", ""});
```

We must help the C++17 compiler by spelling out the type of the appended element.

### QML Runtime Errors

Unfortunately, we don't have a friendly compiler telling us which lines of our QML code are deprecated. The documentation page [Obsolete QML Types](https://doc.qt.io/qt-5/obsoleteqmltypes.html?ref=smallstepsystems.com) lists the known obsolete types, properties and methods. It's worth going through these lists and checking our QML code for problems. I didn't find any problems in the harvester QML code.

Before we test the most common usage scenarios (hopefully in an automated way), we update the versions in the `import` statements. I had to perform the following replacements in the QML files.

```
Qt 5.12                      ->  Qt 5.15
import QtQuick 2.10          ->  import QtQuick 2.15
import QtQuick.Controls 2.3  ->  import QtQuick.Controls 2.15
import QtMultimedia 5.8      ->  import QtMultimedia 5.15
```

In my case, testing the most common usage scenarios unearthed a single problem about signal handlers or slots in `Connections` types.

#### Warning: QML Connections: Implicitly defined onFoo properties in Connections are deprecated

*Problem*:

```
Connections {
    target: csvExportModel
    onMessageOccurred: messagePane.text = message
}
```

The signal handler `onMessageOccurred` is implicitly defined as a function.

*Fix*:

```
Connections {
    target: csvExportModel
    function onMessageOccurred(message)
    {
        messagePane.text = message
    }
}
```

We must define `onMessageOccurred` as a function explicitly with an argument list.

## Migrating from Qt 5.15 to Qt 6.2

It's best to install QtCreator 4.14 or newer, as these versions [fully support Qt 6](https://www.qt.io/blog/qt-creator-4.14-released?ref=smallstepsystems.com). QtCreator 4.14 adds proper syntax highlighting for Qt 6 code and some improvements for CMake. My development PC ran Ubuntu 18.04.

When I installed Qt 6 with the online installer, I encountered this error:

![](https://storage.ghost.io/c/c7/ee/c7ee1cf5-b86f-491b-aab7-20ad081598e1/content/images/2025/11/install-qt6-error-1.png)

My Internet search lead me to [QTBUG-89218](https://bugreports.qt.io/browse/QTBUG-89218?ref=smallstepsystems.com). The comment section reveals that Ubuntu 18.04 is not a [supported development platform](https://www.qt.io/blog/qt6-development-hosts-and-targets?ref=smallstepsystems.com) any more. We have two options. We can upgrade to Ubuntu 20.04 or newer or we can build Qt 6.2 from sources. I decided to upgrade my Ubuntu version.

### Building with CMake

#### Updating CMakeLists.txt Files

The `CMakeLists.txt` files refer to Qt 5 explicitly in `find_package` and `target_link_libraries` commands.

```
find_package(Qt5 COMPONENTS Core Gui Qml REQUIRED)
target_link_libraries(${PROJECT_NAME}
  Ag::Can Ag::Hmi Qt5::Core Qt5::Gui Qt5::Qml
)
```

We must change Qt 5 to Qt 6.

```
find_package(Qt6 COMPONENTS Core Gui Qml REQUIRED)
target_link_libraries(${PROJECT_NAME}
  Ag::Can Ag::Hmi Qt6::Core Qt6::Gui Qt6::Qml
)
```

Qt5 was built on C++11\. The top-level `CMakeLists.txt` file contained the following lines.

```
set(CMAKE_CXX_STANDARD 11)
set(CMAKE_CXX_STANDARD_REQUIRED ON)
```

Qt6 requires C++17\. We must change the top-level `CMakeLists.txt` file accordingly.

```
set(CMAKE_CXX_STANDARD 17)
set(CMAKE_CXX_STANDARD_REQUIRED ON)
```

#### Setting Up the QtCreator Kit

When I started QtCreator the first time after installing Qt 6, the auto-detected kit for Qt 6 was messed up. It referred to outdated C and C++ compilers from a Qt 5.14 installation and the system CMake 3.16 from Ubuntu 20.04\. We can fix this mess in the QtCreator dialog *Tools | Options | Kits*.

- We clone the auto-detected read-only kit for Qt 6.2.
- We define `/usr/bin/gcc` and `/usr/bin/g++` from Ubuntu 20.04 as the new C and C++ *Compilers*. Both compilers are version 9.3\. GCC9 supports C++17\. If we must work with different compiler versions, we set the *Compilers* to `/usr/bin/gcc-9 `and `/usr/bin/g++-9`.
- We define the CMake coming with Qt6 - `/path/to/Qt-6.2.0/Tools/CMake/bin/cmake` (version 3.21) - as the *CMake Tool* of the kit. Qt 6 requires at least CMake 3.18.
- The *CMake generator* is *Ninja* and the extra generator is *<none>*.

When we run CMake to configure the project, the CMake command should look similar to this:

```
/path/to/Qt6.2.0/Tools/CMake/bin/cmake 
    -S /private/Projects/Ag/terminal
    -B /tmp/QtCreator-UDwQep/qtc-cmake-sOofIBPC 
    -GNinja 
    -DCMAKE_BUILD_TYPE:String=Debug
    -DQT_QMAKE_EXECUTABLE:STRING=/path/to/Qt-6.2.0/6.2.0/gcc_64/bin/qmake
    -DCMAKE_PREFIX_PATH:STRING=/path/to/Qt/Qt-6.2.0/6.2.0/gcc_64
    -DCMAKE_C_COMPILER:STRING=/usr/bin/gcc-9
    -DCMAKE_CXX_COMPILER:STRING=/usr/bin/g++-9
```

We can force a re-configuration of the project by removing the build directory recursively and by running *Build | Run CMake*, or by pressing the button *Re-configure with Initial Parameters* on the page *Projects | Build & Run | Desktop Qt 6.2.0 GCC 64bit | Build Settings*.

#### Core5Compat Library

The [Core5Compat library](https://doc.qt.io/qt-6/qtcore5-index.html?ref=smallstepsystems.com) adds the obsolete Qt 5 classes and functions that didn't make it into Qt 6\. We can add `Core5Compat` to the `find_package` commands and `Qt6::Core5Compat` to the `target_link_libraries` commands. If we do, the compiler will flag occurrences of `QRegExp`, `QTextCodec` and some other classes from `Qt6::Core` as warnings instead of errors (see [this post](https://www.qt.io/blog/porting-from-qt-5-to-qt-6-using-qt5compat-library?ref=smallstepsystems.com) for a mapping between obsolete Qt 5 classes and their Qt 6 replacements).

Core5Compat makes the transition from Qt 5 to Qt 6 smoother. We must fix fewer errors before our application builds and runs again. I didn't use Core5Compat, because I learned about it too late. I could fix the resulting errors in a mechanical way like replacing `QRegExp` functions by their counterparts in `QRegularExpression`.

### C++ Compiler Errors and Warnings

#### Modules Missing in Qt 6.0 and 6.1 Now Available in Qt 6.2

Qt 5 modules like Multimedia, SerialBus, SerialPort, RemoteObjects, Virtual Keyboard, Charts, Bluetooth, WebEngine and WebView didn't make it into Qt 6.0 (see [this post](https://www.qt.io/blog/add-on-support-in-qt-6.0-and-beyond?ref=smallstepsystems.com) for a complete list). A few became available in Qt 6.1 (April 2021). [Qt 6.2](https://www.qt.io/blog/qt-6.2-lts-released?ref=smallstepsystems.com), which was released in September 2021, contains all modules from Qt 5.15 and has long-term support.

As the harvester application depends on SerialBus and Multimedia, Qt 6.2 is the first version fit for product releases. With Qt 6.0 and 6.1, I commented out the parts using Multimedia and performed a very quick and very dirty migration of SerialBus. The harvester application uses QtCanBus from SerialBus.

#### New Qt Module StateMachine

The state machine framework with classes like QStateMachine, QState and QFinalState was moved from the module Core to the new module StateMachine. We add `StateMachine` to the `find_package` call and `Qt6::StateMachine` to the `target_link_libraries` call in a *CMakeLists.txt* file.

#### Error: no match for ‘operator<’ (operand types are ‘const QVariant’ and ‘const QVariant’)

*Problem*:

```
QMap<std::pair<QString, QVariant>, QObject *> m_entities;
m_impl->m_entities.insert(it.key(), it.value());
```

The function `it.key()` returns an object of type `std::pair<QString, QVariant`\>, which is the same as the key type of the `QMap`. QMap requires the definition of `operator<` on the key type to know where to insert new values.

`QMap` compares whether the pair `p1` is less than `p2`, where both `p1` and `p2` have the type `std::pair<QString, QVariant>`. If `p1.first` is equal to `p2.first`, the comparison must evaluate `p1.second < p2.second`. G++-9 rightly complains that `operator<` is not defined for `QVariant`s. G++-7 overlooked the missing `operator<` for `QVariant`s.

*Fix*:

```
QMap<std::pair<QString, QString>, QObject *> m_entities;
m_impl->m_entities.insert(it.key(), it.value());
```

Converting a `QVariant` into a `QString` with `QVariant::toString()` works for most types supported by `QVariant`. As `m_entities` only uses supported types for the second element of its key, we can safely replace `QVariant` by `QString` in the key type.

#### Error: QTextCodec: No such file or directory

*Problem*:

```
#include <QTextCodec>
...
QTextStream is{&csvFile};
is.setCodec(QTextCodec::codecForName("ISO-8859-1"));
```

The class `QTextCodec` was removed from Qt 6 and was replaced by the new class `QStringConverter`. Similarly, the classes `QTextEncoder` and `QTextDecoder` were replaced by `QStringEncoder` and `QStringDecoder` (see this [post](https://www.qt.io/blog/porting-from-qt-5-to-qt-6-using-qt5compat-library?ref=smallstepsystems.com)). Code using any of the old classes doesn't compile.

*Fix*:

```
#include <QStringConverter>
...
QTextStream is{&csvFile};
is.setEncoding(QStringConverter::Latin1);
```

We include the header of the replacement class `QStringConverter`. A search through the functions of `QStringConverter` makes `setEncoding` the most likely replacement for `setCodec`. Understanding that ISO-8859-1 is the formal name for Latin1 helps us call `setEncoding` with the right constant `QStringConverter::Latin1`.

#### Error: QRegExp: No such file or directory

Problem:

```
#include <QRegExp>

// In anonymous namespace
QRegExp &rxHexFilename()
{
    static QRegExp rx("_(A\\d\\d)_V_(\\d\\d)_(\\d\\d)\\.hex$");
    return rx;
}

// In constructor
auto pos = rxHexFilename().indexIn(fileName);
auto ecuName = rxHexFilename().cap(1);
if (pos == -1 || ...) {
    return;
}
m_version = QString("v%1.%2")
    .arg(rxHexFilename().cap(2).toUInt())
    .arg(rxHexFilename().cap(3).toUInt());
m_ecuType = fileName.left(fileName.size() - 
    rxHexFilename().matchedLength());
```

Replacing `QRegExp` \- a relic of Qt 4 - by `QRegularExpression` has been in the making since Qt 5.0\. `QRegularExpression` is the only way to work with regular expressions in Qt 6\. The interface has changed considerably.

Fix:

```
#include <QRegularExpression>

// In anonymous namespace
const QRegularExpression rxHexFilename("_(A\\d\\d)_V_(\\d\\d)_(\\d\\d)\\.hex$");

// In constructor
auto match = rxHexFilename.match(fileName);
auto ecuName = match.captured(1);
if (!match.hasMatch() || ...) {
    return;
}
m_version = QString("v%1.%2")
    .arg(match.captured(2).toUInt())
    .arg(match.captured(3).toUInt());
m_ecuType = fileName.left(fileName.size() - 
    match.capturedLength(0));
```

The function for matching a string against a regular expression has got its natural name: `match` (instead of `indexIn`). It returns a `QRegularExpressionMatch` object `match` instead of an index. We retrieve the `nth` captured substring by calling `match.captured(nth)`. match.hasMatch() tells us whether the string matched the regular expression.

`QRegExp::matchedLength` returns the length of the substring matching the complete regular expression. This substring is the same as the 0th captured substring `match.captured(0)`, which has the length `match.capturedLength(0)`.

#### Error: ‘class QString’ has no member named ‘midRef’

*Problem*:

```
subDev = m_deviceName.midRef(splitPos + 1).toLatin1();
```

The function `QString::midRef` is obsolete in Qt 6\. The same goes for the function `QString::leftRef`.

*Fix*:

```
subDev = m_deviceName.mid(splitPos + 1).toLatin1();
```

We replace `QString::midRef` and `QString::leftRef` by `QString::mid` and `QString::left`, respectively.

#### Error: cannot convert ‘QString’ to ‘const QFileInfo&’

*Problem*:

```
QString extractVersion(const QFileInfo &info) const;

QString fileName(...);
auto version = extractVersion(fileName);
```

In Qt 5, the function `extractVersion` implicitly converts the `QString` `filename` into a `QFileInfo` object with the constructor `QFileInfo(const QString &)`. In Qt 6, this constructor is marked `explicit`, which blocks the implicit conversion.

*Fix*:

```
QString extractVersion(const QFileInfo &info) const;

QString fileName(...);
auto version = extractVersion(QFileInfo(fileName));
```

We get rid of the error by calling the constructor `QFileInfo(const QString &)` explicitly.

#### Error: invalid application of ‘sizeof’ to incomplete type ‘IntegerRangeModel’

*Problem*:

```
class IntegerRangeModel;

class DateTimeModel : public QObject
{
    Q_OBJECT
    Q_PROPERTY(IntegerRangeModel* days READ days CONSTANT)
```

The forward declaration of `IntegerRangeModel` was good enough for the `Q_PROPERTY` definition in Qt 5, because `days` is declared as a pointer. Qt 6 added a static assertion. A further error message documents the violation of the static assertion:

```
static_assert(sizeof(T), "Type argument of Q_PROPERTY or Q_DECLARE_METATYPE(T*) must be fully defined");
```

*Fix*:

```
#include "IntegerRangeModel.h";

class DateTimeModel : public QObject
{
    Q_OBJECT
    Q_PROPERTY(IntegerRangeModel* days READ days CONSTANT)
```

We eliminate the error message by including the header file for `IntegerRangeModel` instead of forward declaring `IntegerRangeModel`.

#### Warning: ‘Type’ is deprecated: Use QMetaType::Type instead. \[-Wdeprecated-declarations\]

*Problem*:

```
EntityColumn(const QString &name, QVariant::Type type, ...)
```

The enumeration `QVariant::Type` lists the types that can be stored in a `QVariant`. It is roughly a subset of the enumeration `QMetaType::Type`, which lists the types that are known to Qt's meta object system. Replacing `QVariant::Type` by `QMetaType::Type` suggested itself. `QVariant::Type` is not contained in Qt 6 any more.

*Fix*:

```
EntityColumn(const QString &name, QMetaType::Type type, ...)
```

In Qt 6, we use `QMetaType::Type` instead of `QVariant::Type`. We must also replace obsolete enum constants like `QVariant::Invalid`, `QVariant::UInt` and `QVariant::Bool` by `QMetaType::UnknownType`, `QMetaType::UInt` and `QMetaType::Bool`, respectively.

#### Error: cannot convert ‘QVariant::Type’ to ‘QMetaType::Type’

*Problem*:

```
bool typesAreAffine(QMetaType::Type sqlType, ...) const;

QSqlField tableColumn = ...;
if (!typesAreAffine(tableColumn.type(), ...)) ...
```

Originally, the first argument of `typesAreAffine` had the type `QVariant::Type`, which was replaced by `QMetaType::Type` by the previous migration step. The function `QSqlField::type` with the return type `QVariant::Type` doesn't exist in Qt 6.

*Fix*:

```
bool typesAreAffine(QMetaType::Type sqlType, ...) const;

QSqlField tableColumn = ...;
if (!typesAreAffine(QMetaType::Type(tableColumn.metaType().id()), ...)) ...
```

We substitute the Qt 6 function `QSqlField::metaType()` for the now obsolete Qt 5 function `QSqlField::type()`. `QSqlField::metaType()` returns a `QMetaType` object. We retrieve the type ID of the `QMetaType` object with `id()`, which returns an `int` instead of a `QMetaType::Type` to be open for custom meta types. `QMetaType::Type(typeID)` creates a enum constant from the integer `typeID`.

#### Error: warning: conversion from ‘qsizetype’ {aka ‘long long int’} to ‘int’ may change value \[-Wconversion\]

*Problem*:

```
QList<QFileInfo> m_dirEntries.

int DirectoryModel::rowCount(const QModelIndex &parent) const
{
    Q_UNUSED(parent)
    return m_impl->m_dirEntries.size();
}
```

Starting with Qt 6.0, `QList<T>::size()` has the return type `qsizetype`, which is equivalent to `long long int`. The class DirectoryModel indirectly derives from `QAbstractItemModel`, which declares the pure virtual function `rowCount` like this:

```
virtual int rowCount(const QModelIndex &parent = QModelIndex()) const = 0
```

The `return` statement may narrow a `long long int` value to an `int` value, which may change the value. It seems that the Qt developers forgot to change the return type of `rowCount` from `int` to `qsizetype`.

Functions like `beginInsertRows`, `beginRemoveRows`, `beginMoveRows` and `beginInsertColumns` also take `int`\-type arguments. We may have to watch out for narrowing conversions as well.

*Fix*:

```
QList<QFileInfo> m_dirEntries.

int DirectoryModel::rowCount(const QModelIndex &parent) const
{
    Q_UNUSED(parent)
    return static_cast<int>(m_impl->m_dirEntries.size());
}
```

Sometimes there is no way around a static cast. This is one of those times. We force the `qsizetype` value into an int `value` and silence the error.

#### Warning: conversion from ‘size\_t’ {aka ‘long unsigned int’} to ‘uint’ {aka ‘unsigned int’} may change value \[-Wconversion\]

Problem:

```
enum class UnitId : quint16 { ... }

inline uint qHash(UnitId unit)
{
    return qHash(static_cast<quint16>(unit));
}
```

`qHash` functions return `uint` values in Qt 5, where `uint` is `unsigned int`. In Qt 6, they return `size_t` values, where `size_t` is `long unsigned int`. The `qHash` function in the `return` statement is a built-in hash function. It returns a `long unsigned int` value, which may be narrowed to a an `unsigned int` value by the custom-defined hash function. As this may change the value, the compiler emits a warning.

Fix:

```
enum class UnitId : quint16 { ... }

inline size_t qHash(UnitId unit)
{
    return qHash(static_cast<quint16>(unit));
}
```

We change the return type of the custom-defined hash function from `uint` to `size_t`.

#### Warning: ‘static QQmlFileSelector\* QQmlFileSelector::get(QQmlEngine\*)’ is deprecated \[-Wdeprecated-declarations\]

*Problem*:

```
auto fs = QQmlFileSelector::get(engine);
fs->setExtraSelectors({"left"});
```

The static function `QQmlFileSelector::get` returns the file selector currently active on the QML `engine`. It is obsolete in Qt 6, because it duplicates the functionality provided by the `QQmlFileSelector` constructor.

*Fix*:

```
auto fs = new QQmlFileSelector(engine);
fs->setExtraSelectors({"left"});
```

Creating a `QQmlFileSelector` object on the heap does the same as calling `QQmlFileSelector::get`. We must create the object on the heap, because the constructor argument `engine` takes ownership of the file selector.

#### Error: using typedef-name ‘using QStringList = class QList<QString>’ after ‘class’

*Problem*:

```
class QStringList;
```

An included Qt header file introduces the type definition `using QStringList = class QList<QString>`. The problematic line forward declares this type definition, which the compiler doesn't like.

*Fix*:

```
#include <QStringList>
```

We replace the forward declaration by the inclusion of the header file.

#### Error: ‘QLatin1Literal’ was not declared in this scope; did you mean ‘QStringLiteral’?

*Problem*:

```
QStringList errors;
Q_ASSERT_X(false, __PRETTY_FUNCTION__, 
    errors.join(QLatin1Literal("; ")).toUtf8());
```

`QLatin1Literal` doesn't exist in Qt 6 any more.

*Fix*:

```
QStringList errors;
Q_ASSERT_X(false, __PRETTY_FUNCTION__, 
    errors.join(QLatin1String("; ")).toUtf8());
```

We replace `QLatin1Literal` by `QLatin1String`.

#### Error: No type name 'State' in QMediaPlayer

*Problem:*

```
void onStateChanged(QMediaPlayer::State state);

connect(&m_impl->m_player, &QMediaPlayer::stateChanged,
        m_impl, &Impl::onStateChanged);

if (m_player.state() != QMediaPlayer::PlayingState) { ... }
```

We replace `QMediaPlayer::State` by `QMediaPlayer::PlaybackState` and connect the slot `onStateChanged` with the signal `QMediaPlayer::playbackStateChanged`. We also need to replace calls to `QMediaPlayer::state()` by `QMediaPlayer::playbackState()`.

*Fix:*

```
void onStateChanged(QMediaPlayer::PlaybackState state);

connect(&m_impl->m_player, &QMediaPlayer::playbackStateChanged,
        m_impl, &Impl::onStateChanged);

if (m_player.playbackState() != QMediaPlayer::PlayingState) { ... }
```

#### Error: 'QMediaPlaylist': No such file or directory

*Problem:*

```
#include <QMediaPlaylist>
```

The page [Changes to Qt Multimedia](https://doc.qt.io/qt-6/qtmultimedia-changes-qt6.html?ref=smallstepsystems.com) informs us that the class `QMediaPlaylist` was removed from Qt 6\. The application plays different MP3 files when info, warning or error dialogs are shown. It passes a `QMediaPlaylist` with the correct MP3 file to `QMediaPlayer`. Users can also change the playback volume.

*Fix:*

`QMediaPlaylist` is replaced by `QMediaPlayer::setSource`. The volume cannot be changed directly with `QMediaPlayer::setVolume` but is changed indirectly with `QAudioOutput::setVolume`. The following error messages about QMediaPlayer and QMediaPlaylist tell us what to fix.

#### Error: No member named 'setVolume' in 'QMediaPlayer'

*Problem:*

```
m_player.setVolume(80);
```

Qt 6 moved the functions `setVolume` and `volume` from `QMediaPlayer` to `QAudioOutput`.

*Fix:*

The client class using `QMediaPlayer` must register a `QAudioOutput` object with the `QMediaPlayer` object `m_player` in its constructor. We must tell the `QAudioOutput` object on which loudspeaker it shall play the MP3 file. We can access the default loudspeaker with `QMediaDevices::defaultAudioOutput`. That's good enough for the terminal hardware, which has only one loudspeaker.

The client class sets the volume to a default value (e.g., 0.8). Note that the new `QAudioOutput::setVolume` takes a floating-point value between 0.0 and 1.0 as an argument, whereas the old `QMediaPlayer::setVolume` took an integer between 0 and 100.

```
auto audioOut = new QAudioOutput{};
audioOut->setDevice(QMediaDevices::defaultAudioOutput());
audioOut->setVolume(0.8f);
m_player.setAudioOutput(audioOut);
```

The `setVolume(int vol)` function of the client class changes the volume like this:

```
m_player.audioOutput()->setVolume(0.8f);
```

#### Error: QMediaPlayer cannot play back a QMediaPlaylist any more

*Problem:*

Of course, the title error message is not a real compiler error. As QMediaPlaylist was removed from Qt 6, the following playback function of an error category does not compile any more.

```
void AudioService::Impl::playFeedback(int category)
{
    m_playlist.addMedia(m_audioFiles[category]);
    m_player.play();
}
```

`m_audioFiles[category]` returns the QRC URL of the MP3 file for the given error `category`. For example, it returns `QUrl("qrc:/Can/Audio/ding.mp3")` for the category 2.

*Fix:*

The modified function for playing an MP3 file for the given `category` looks as follows.

```
void AudioService::Impl::playFeedback(int category)
{
    m_player.setSource(m_audioFiles[category]);
    m_player.play();
}
```

### QML Warnings, Errors and Improvements

#### Remove versions from import statements

*Problem:*

```
import QtQuick 2.15
import QtQuick.Controls 2.15
import Ag.Models 1.0
```

Qt 5 requires a version for the imported modules. Qt 6 doesn't complain about these versions, but it doesn't require them any more.

*Fix:*

```
import QtQuick
import QtQuick.Controls
import Ag.Models
```

Just importing a module without a version is enough in Qt 6\. We remove the versions from all the import statements.

#### Warning: Parameter "page" is not declared. Injection of parameters into signal handlers is deprecated.

*Problem:*

```
// File: RDirectBar.qml
Pane 
{
    signal selectedPage(url page, bool fullscreen)

// File: main.qml
RDirectBar
{
    onSelectedPage: { ... }
```

The signal `selectedPage` is connected to the signal handler `onSelectedPage` in the instantiation of `RDirectBar`. Qt 6 accepts the old-style signal handlers with a warning.

*Fix:*

The new way is to use arrow functions or anonymous functions (see [Signal Parameters](https://doc.qt.io/qt-6/qtqml-syntax-signals.html?ref=smallstepsystems.com#signal-parameters) in the Qt 6.2 documentation). We would call them lambda functions in C++.

```
// File: RDirectBar.qml
Pane 
{
    signal selectedPage(url page, bool fullscreen)

// File: main.qml
RDirectBar
{
    // Arrow function
    onSelectedPage: (page, fullscreen) => { ... }

    // Anonymous function (alternative)
    onSelectedPage: function (page, fullscreen) { ... }
```

Signal handlers without parameters need not be changed from Qt 5 to Qt 6.