Porting code from Qt 1.0 to Qt 5.11

Original author: Paul Olav Tvete
  • Transfer
Qt 5.11 was recently released and I thought that now is the time to upgrade some of my Qt 1.0 projects to it ... Okay, just kidding :) Actually, I wondered how well we managed to maintain backward compatibility for all these years of development of the Qt framework code.

Qt guarantees compatibility at the level of code and binaries when updating between minor versions of the framework (and we take this promise seriously). You do not have to rewrite (or even recompile) your code when upgrading to another minor version of Qt. However, transitions between major versions required us to make some sacrifices for the sake of progress. Since the release of Qt 1.0 in 1996, we have broken code compatibility four times: in versions 2.0, 3.0, 4.0 (oh, it was painful!) And 5.0.

We tried even in major versions to break as little as possible of everything, but still it had to be done. This raises the question: how difficult is it to port an application written in Qt 1.0 to modern Qt 5.11?

To answer this question, I took a sample of the code that came with Qt 1.0 documentation and tried to compile it with Qt 5. Our public archives contain changes since version 1.41, so I had to dig a little into the most recent history, go through the logs of four different version control systems ... but I already get distracted. The project I plan to build is called “t14” - because this is an illustration of the 14th (and last) chapter of the original manual.

And that's what I had to do to build it.

We import the original project : 10 files changed, 798 insertions (+) A
pure work of art: in 1996, it was officially recommended to write programs on Qt.

Moving to qmake : 3 files changed, 2 insertions (+), 148 deletions (-)

image

Before the release of qmake was tmake. It was written in Perl. The basic syntax was similar, only tmake still allowed to include Perl code directly in the project file, which (fortunately!) Cannot be done in qmake. In addition, tmake was not a publicly described part of the framework, so we prepared makefiles for releases. Having a completely different internal and external code assembly system has always added an element of surprise to releases.

Fix the include files :4 files changed, 8 insertions (+), 8 deletions (-)

image

In those ancient times when this example was written, Windows limited the length of the file name to 8 characters. Of course, we could have guided Unix and made normal names, but if the code had to be portable, we had to use “delightful” file names like “qscrbar.h” and “qbttngrp.h”.

Add missing include files : 1 file changed, 3 insertions (+)
Dependencies on implicit inclusions were and remain a problem.

Change TRUE / FALSE to true / false : 1 file changed, 13 insertions (+), 13 deletions (-)

image

Oh, those kids today. Happiness of their not aware! We were forced to write our own boolean data type, since we didn’t have a built-in language!

Correct references to entities that have moved to the Qt namespace : 3 files changed, 15 insertions (+), 15 deletions (-)

image

Qt was added in 1998 and was then ... a class. Yes, a class because we didn’t have namespaces then.

We remove the name argument : 6 files changed, 26 insertions (+), 26 deletions (-)

image

All constructors of QObject subclasses took the object name as a parameter.

QScrollBar class API changed : 1 file changed, 5 insertions (+), 5 deletions (-)

image

Sometimes we had to get rid of old, poorly designed APIs. Using individual setters is a much better practice than a constructor taking 7 arguments.

We use QString instead of const char * : 2 files changed, 2 insertions (+), 2 deletions (-)

image

QString has existed in Qt since 1994. Previously, it was a Latin-encoded 8-bit string with automatic conversion to const char *, so the API used arguments of the const char * type here and there. Unicode support appeared in Qt 2.0.

warning () is now called qWarning () : 1 file changed, 1 insertion (+), 1 deletion (-)
We generally avoid adding entities to the global namespace. Well, except that if they begin on "Q". This letter belongs to us.

We remove unnecessary calls to the old QApplication methods : 1 file changed, 2 deletions (-)

image

Qt today does a lot of things on its own, well and automatically. And in 1996, many displays could only display 8 bits per pixel, so more than 256 colors had to be tried to display.

Replacing QAccel with QShortcut : 1 file changed, 4 insertions (+), 3 deletions (-)

image

QShortcut is both more powerful and simpler. And its name is not an abbreviation. QShortcut was added in 2004.

Correcting redraw logic : 1 file changed, 7 insertions (+), 7 deletions (-)

image

In the 90s, we could draw directly on widgets whenever we wanted. Today we have buffering and composition, so everything becomes more complicated and easier at the same time. We send a change request and later, when we receive a signal to redraw, draw. Slightly more code, but much more logical.

QObject :: killTimers () no longer exists : 2 files changed, 3 insertions (+), 2 deletions (-)

image

This function was too dangerous. She killed all object timers, including those used inside Qt. Today you must kill timers consciously and individually.

QWMatrix is ​​now called QMatrix : 1 file changed, 2 insertions (+), 2 deletions (-)
Just changing the class name.

The QWidget :: setBackgroundColor () method has been removed :1 file changed, 3 insertions (+), 1 deletion (-)

image

The background color of the widget is no longer so simple: it is encapsulated inside a QPalette along with other properties. In addition, child widgets are now transparent by default. We need to tell Qt exactly how we want to draw the background.

I can't fill the pixmap with the widget contents : 1 file changed, 1 insertion (+), 1 deletion (-)

image

I used a transparent pixmap for this, since Qt now supports them.

Drawing rectangles has changed : 1 file changed, 1 insertion (+), 1 deletion (-)

image

This is probably the most radical change of all of the above. Starting with Qt 4.0, the QPainter :: drawRect () method has been modified so that “the hatching rectangle has the size of rectangle.size () + width of the pen”. Thus, we need to subtract the width of the pen (in our case it is 1) before passing the rectangle to QPainter.

Now we have a full-featured example port from the original tutorial, here's a screenshot:

image

Oh ... In some places, the text looks cropped. It turned out that this happened because of the sizes and positions of the elements, which are strictly stated in the code, and the font sizes, it turns out, have changed since 1996. The solution is to use QLayout, which was not available during Qt 1.0 (the first version appeared in Qt 1.1. And was completely rewritten by Qt 2.0).

Use QLayout instead of hard-coded dimensions : 4 files changed, 29 insertions (+), 24 deletions (-)

image

And with this, the last, change, everything finally looks as it should:

image

What is the moral of this story? We succeeded (and it didn’t even take a lot of time) to port 22-year-old code from Qt 1.0 to Qt 5.11. This is possible. It probably took me more time to write this article than to edit the code itself. Most APIs are still alive in recent Qt versions, even after so many years and versions. Some of them have remained unchanged, others have been expanded and improved, but still retain recognition. All changes were aimed at improving the readability, security, maintainability and performance of Qt applications.

Also popular now: