Thursday, March 11, 2010

Code snippet: QLabel to show remote pixmap by URL

Perhaps one of the most often used widgets in Qt is QLabel. It is mainly used to display a plain text as well as rich one (which contains HTML markup). QLabel is also able to show graphics by passing QPixmap instance to it. But what if there is a need to display (using QLabel) a pixmap stored on remote server? There is no such "out of the box" functionality in QLabel. But it can be easily done. Here I want to show you how.

We just make a derivative class of QLabel and add only one new public method -- setRemotePixmap(const QString&) to let the label know that we want to display a remote graphics. Then the label composes HTTP GET request using QNetworkAccessManager class to retrieve the file. When the image is retrieved, it is showed up using setPixmap(const QPixmap&).

Let's see the source code.


The source
Header: RemotePixmapLabel.h
/* RemotePixmapLabel -- custom Qt QLabel widget to show remote (by URL) pixmaps.
 *
 * Author: Andrew Sichevoi, http://thekondor.net
 *
 * THIS CODE SNIPPET IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
 * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF THIRD PARTY RIGHTS.
 */

#ifndef REMOTE_PIXMAP_LABEL_H
#define REMOTE_PIXMAP_LABEL_H

#include <qtgui/qlabel>
#include <qtcore/qstring>
#include <qtnetwork/qnetworkaccessmanager>
#include <qtnetwork/qnetworkreply>

class RemotePixmapLabel: public QLabel
{
    Q_OBJECT
public:
    RemotePixmapLabel(QWidget* parent = 0) : 
        QLabel(parent), networkManager(0)
    {}
    RemotePixmapLabel(const QString& text, QWidget* parent = 0) :
        QLabel(text, parent), networkManager(0)
    {
    }
public slots:
    void setRemotePixmap(const QString& /* url */);
private slots:
    void pixmapReceived(QNetworkReply*);
private:
    QNetworkAccessManager* networkManager_;
};

#endif

And the implementation (RemotePixmapLabel.cpp):
/* RemotePixmapLabel -- custom Qt QLabel widget to show remote (by URL) pixmaps.
 *
 * Author: Andrew Sichevoi, http://thekondor.net
 *
 * THIS CODE SNIPPET IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
 * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF THIRD PARTY RIGHTS.
 */

#include "RemotePixmapLabel.h"

#include <QtGui/QPixmap>
#include <QtCore/QUrlgt;
#include <QtCore/QDebuggt;

void RemotePixmapLabel::setRemotePixmap(const QString& url)
{
    /* Here might be the work with the cached pixmaps */

    if (!networkManager_) {
        /* Lazy initialization of QNetworkAccessManager;
         * only 1 instance is required;
         */
        networkManager_ = new QNetworkAccessManager(this);
        connect(networkManager_, SIGNAL(finished(QNetworkReply*)),
                this, SLOT(pixmapReceived(QNetworkReply*)));
    }

    /* Send GET request to obtain the desired picture */
    networkManager_->get(QNetworkRequest(QUrl(url)));
}

void RemotePixmapLabel::pixmapReceived(QNetworkReply* reply)
{
    if (QNetworkReply::NoError != reply->error()) {
        qDebug() << Q_FUNC_INFO << "pixmap receiving error" << reply->error();
        reply->deleteLater();
        return;
    }

    const QByteArray data(reply->readAll());
    if (!data.size())
        qDebug() << Q_FUNC_INFO << "received pixmap looks like nothing";

    QPixmap pixmap;
    pixmap.loadFromData(data);
    setPixmap(pixmap);

    reply->deleteLater();
}

How to use
Add QLabel to your widget/dialog/window using Qt Designer. Promote newly created QLabel to RemotePixmapLabel setting an #include file to RemotePixmapLabel.h. And that's all. Next you just use setRemotePixmap(const QString&) to specify the source of a picture you want to display on.

This is a very basic implementation. The more advanced one is to prevent a repeated retrieving of the same picture several times -- to add caching. It's also done easily enough -- try to implement it yourself and you will definitely have some fun.
Beside the basics it is a very straightforward implementation. From the design point of view, it is not good to delegate retrieving of remote image to QLabel. The best approach is to delegate it to QPixmap.

1 comment: