QML and C ++ image compatibility
This could have been done in QtQuick1, but this feature has been removed in QtQuick2.
The solution I came up with allows you to have the same image in QML and C ++ by implementing QQuickImageProvider
which basically works with QPixmap *
, which is converted to a string and then back to a pointer type (it sounds a bit unsafe, but it turns out that it is works very well).
class Pixmap : public QObject {
Q_OBJECT
Q_PROPERTY(QString data READ data NOTIFY dataChanged)
public:
Pixmap(QObject * p = 0) : QObject(p), pix(0) {}
~Pixmap() { if (pix) delete pix; }
QString data() {
if (pix) return "image://pixmap/" + QString::number((qulonglong)pix);
else return QString();
}
public slots:
void load(QString url) {
QPixmap * old = 0;
if (pix) old = pix;
pix = new QPixmap(url);
emit dataChanged();
if (old) delete old;
}
void clear() {
if (pix) delete pix;
pix = 0;
emit dataChanged();
}
signals:
void dataChanged();
private:
QPixmap * pix;
};
The implementation of the element is Pixmap
pretty straightforward, although the initial part was a bit limited, since the new pixmap was allocated to exactly the same memory address, the line data
was the same for different images, which caused the QML Image component not to update, but the solution was as simple as removing the old one pixmap only after a new one has been selected. Here is the actual image provider:
class PixmapProvider : public QQuickImageProvider {
public:
PixmapProvider() : QQuickImageProvider(QQuickImageProvider::Pixmap) {}
QPixmap requestPixmap(const QString &id, QSize *size, const QSize &requestedSize) {
qulonglong d = id.toULongLong();
if (d) {
QPixmap * p = reinterpret_cast<QPixmap *>(d);
return *p;
} else {
return QPixmap();
}
}
};
Check in:
//in main()
engine.addImageProvider("pixmap", new PixmapProvider);
qmlRegisterType<Pixmap>("Test", 1, 0, "Pixmap");
And this is how you use it in QML:
Pixmap {
id: pix
}
Image {
source: pix.data
}
// and then pix.load(path)
ALSO Note that in my case there was no actual pixmap modification that needed to be updated in QML. This solution will not automatically update the image in QML if changed in C ++ because the memory address will remain the same. But the solution for this is just as simple - implements a method update()
that allocates new QPixmap(oldPixmap)
- it will use the same internal data, but will give you a new accessor to it with a new memory address that will trigger the QML image to update the changes. This means that the suggested pixmap accessor will go through the class Pixmap
and not directly from QPixmap *
, as you will need the class Pixmap
to trigger the change data
, so just add an accessor forpix
and just in case you are doing complex or multi-threaded things, you can use QImage
and add a mutex instead so that the underlying data does not change in QML when changed to C ++ or vice versa.
source to share