Porting Desktop Applications from Qt 4 to Qt 5
Introduction
Now that Qt 5.0.0 is officially out, as an experiment to gain more experience with porting desktop applications from Qt 4 to Qt 5, I tried porting the example applications that came with the book C++ GUI Programming with Qt 4 by Jasmin Blanchette and Mark Summerfield.
I used the first edition of the book from 2006. There is a second edition that came out in 2008 but I didn't have a copy of it handy. The examples consist of about 60 qmake project files and approximately 14,000 lines of C++ code. The example code dates back to about 2006 and at the time Qt version 4.1 was current. They all build fine with the most recent version of Qt 4, 4.8.4.
My goal was to see if I could port the code to Qt 5, see what issues I encountered, and how much effort it took to do the porting. I used the Qt 5.0.0 release.
Common Changes
For any application that uses widgets (which is most of the examples I ported), widgets are now optional and need to be added to the qmake project file. I typically add this line near the top of the .pro file that only adds the widgets module if the Qt version is 5 or later:
greaterThan(QT_MAJOR_VERSION, 4): QT += widgets
While it is not best practice, a lot of the applications used the <QtGui> header file to pull in all of the headers for the GUI classes. In general it is better to include only the header files for the classes you use, but this is common for example applications where the author wants to keep the code listings short.
In Qt 4 <QtGui> included the widget classes. In Qt 5 the widgets are in a separate <QtWidgets> header file . So I typically had to add these lines to any header file that included <QtGui> and used widget classes if I wanted it to be compatible with both Qt 4 and Qt 5:
#if QT_VERSION >= 0x050000 #include <QtWidgets> #endif
Miscellaneous Changes
The above two changes were enough to get many of the applications working under Qt 5. Some applications had some additional miscellaneous changes needed which I will discuss here.
In Qt 5 the QRegion method intersect() now has the name intersected(). The new method was introduced in Qt 4.4 and the old one removed in Qt 5. For changes of this type I used ifdefs to keep the code compatible with the original Qt 4 version, e.g.
#if QT_VERSION >= 0x050000 if (!event->region().intersected(rect).isEmpty()) { #else if (!event->region().intersect(rect).isEmpty()) { #endif
Although in this case the new code works with Qt 4.4 and later, so unless there was a reason to remain compatible with Qt versions prior to 4.4, the method could simply be changed.
Several examples made use of Qt Designer plugins. In Qt 5 the plugin architecture has changed somewhat. The macro Q_EXPORT_PLUGIN is no longer used and will produce an error during compilation. Instead you use the new macro Q_PLUGIN_METADATA. There is a good example in the Qt 5 documentation of how to write a Qt Designer plugin.
One of the examples showed an MDI interface and used the QWorkspace class. This class is obsolete and was replaced by the QMdiArea class in Qt 4.3. In Qt 5 QWorkspace has been removed. The new class has a similar API to QWorkspace and porting it only involved changing the names of a few methods, signals, and slots.
A couple of programs called QAbstractItemModel::reset(). Since Qt 4.6 it has been recommended to beginResetModel() and endResetModel() instead. In Qt 5 reset() was removed. I changed the code to call the newer methods.
One example called QHeaderView::setResizeMode(). In Qt 5 this was renamed tosetSectionResizeMode().
A couple of applications used the method QDir::convertSeparators(). Since Qt 4.2 it is recommended to use QDir::toNativeSeparators().
Three examples (ftpget, httpget, and spider) used the classes QFtp and QHttp. Instead of these classes it is recommended to use the classes QNetworkAccessManager and QNetworkReplywhich were introduced in Qt 4.4, as these classes offer a simpler and more powerful API. In Qt 5 these classes were removed. They are still available as optional add-on modules QtFtp and QtHttp. Because the applications would need significant changes to use the new classes, I did not port them.
Summary
With the above changes I was able to build and run the examples under Qt 5. It took about two hours, mostly making the same simple changes. After porting, the code still builds with Qt 4.
Note that in that time I didn't do full testing of all applications. I got them to compile and build and quickly tested most of them. There could be some Qt 5 related issues that only show up at run-time.
This is by no means an exhaustive list of porting issues, it only describes the ones I encountered. There are several good sections in the Qt documentation that can help with porting, most notably "What's New in Qt 5", "New Classes and Functions in Qt 5", "Porting Guide", and "Porting C++ Applications to Qt 5".
I didn't make any changes to take advantage of the new features of Qt 5, such as the new signal/slot connection syntax. I also didn't cover porting of QML code, which I might discuss in a future blog posting.
I did all my porting work on a Linux system. There are three examples using ActiveX which is Windows only, so I did not look at porting these to Qt 5.
In summary, in a couple of hours, most of which was repetitive editing, I was able to convert a significant body of desktop widget-based Qt 4 code to Qt 5. The code was relatively old and based on Qt 4.1. A more recent code base using Qt 4.7 or 4.8 would have required even fewer changes. The ported code also still continued to build with Qt 4. My experience was that Qt 5 certainly met or exceeded the claim of 99% source compatibility with Qt 4.