A year ago I migrated an old Qt4 project to Qt5. The migration was relatively painless and a huge success with the exception of the QGLWidget powered OpenGL canvas. In Qt5, this widget has been deprecated and currently mangles text rendering on Mac OS X retina displays as shown below:


The only way to fix the mangled text is to migrate to the QOpenGLWidget that was introduced in Qt 5.4.0. Overall, this widget is pretty similar to QGLWidget and Qt has done a decent job describing the differences as well as providing an example of working code.

With that information in hand, I decided to try my luck migrating it over the weekend where I ran into some trouble. Here are some of the more annoying differences that I discovered:

  1. qglColor(), qglColorClear(), bindTexture(), and renderText() are not available.
  2. QPixmaps aren’t supported anymore and you need to substitute QOpenGLTexture.
  3. updateGL() has been renamed to update()
  4. Blending seems to behave differently when utilized with multiple transparent textures.

Some of these things are obvious to fix and others not so much. I was able to easily replace qglColor() and qglColorClear() with by their OpenGL equivalents by looking at the QGLWidget documentation.

void MapCanvas::qglColor(QColor color) {
    glColor4f(color.redF(), color.greenF(), color.blueF(), color.alphaF());
} void MapCanvas::qglClearColor(QColor clearColor) {
    glClearColor(clearColor.redF(), clearColor.greenF(), clearColor.blueF(), clearColor.alphaF());

bindTexture() does not exist anymore so you now need to preload a QOpenGLTexture and then call texture->bind() wherever you called bindTexture() previously.

Additionally, you will need to load textures in the following manner whereas you could just use QPixmap previously:

    QOpenGLTexture *texture = new QOpenGLTexture(QImage(QString(":/pixmaps/terrain%1.png").arg(i)).mirrored());

renderText() was a bit trickier to replace and requires a QPainter to paint text over the OpenGL canvas. I found this solution from jaba on Stackoverflow but discovered a bug (he wasn’t calling painter.end() which resulted in some artifacts). Please also note that the project() method should be what you’re using to project from the OpenGL coordinates to your widget coordinates.

void MapCanvas::renderText(double x, double y, double z, const QString &str, const QFont & font = QFont()) {
    // Identify x and y locations to render text within widget
    int height = this->height();
    GLdouble textPosX = 0, textPosY = 0, textPosZ = 0;
    project(x, y, 0f, &textPosX, &textPosY, &textPosZ);
    textPosY = height - textPosY; // y is inverted

    // Retrieve last OpenGL color to use as a font color
    GLdouble glColor[4];
    glGetDoublev(GL_CURRENT_COLOR, glColor);
    QColor fontColor = QColor(glColor[0], glColor[1], glColor[2], glColor[3]);

    // Render text
    QPainter painter(this);
    painter.drawText(textPosX, textPosY, text);

Unfortunately, the transparent textures artifact problem was not something that I was able to fix entirely. I achieved a similar look by removing most instances of blending and instead utilized colors with a predefined alpha.

Good luck!