我已经查阅了文档以及在互联网上找到的所有信息,但似乎无法从C++中访问QML图像。
是否有解决办法?
在QtQuick1中是可能实现的,但是这个功能在QtQuick2中已被移除。
我想到的解决方案是通过实现一个QQuickImageProvider
来在QML和C++中使用相同的图像。这个提供者基本上使用QPixmap *
,将其转换为字符串,然后再将其转换回指针类型(这听起来有点不安全,但已经被证明可以工作得很好)。
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;
};
Pixmap
元素的实现非常简单,尽管初始时有一些限制,因为新的pixmap恰好被分配到与不同图像的data
字符串相同的内存地址上,导致QML Image组件无法更新,但解决方案很简单,只需在新pixmap分配后删除旧的pixmap即可。以下是实际的图像提供程序:
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();
}
}
};
注册:
//in main()
engine.addImageProvider("pixmap", new PixmapProvider);
qmlRegisterType<Pixmap>("Test", 1, 0, "Pixmap");
这是在QML中使用它的方法:
Pixmap {
id: pix
}
Image {
source: pix.data
}
// and then pix.load(path)
update()
方法,分配一个new QPixmap(oldPixmap)
,它将使用相同的内部数据但为其提供一个新的访问器和一个新的内存地址,这将在更改时触发QML图像更新。这意味着访问pixmap的推荐方法将是通过Pixmap
类,而不是直接从QPixmap *
,因为你需要Pixmap
类来触发data
更改,因此只需添加一个pix
访问器。如果你做复杂或多线程的操作,你可能需要使用QImage
并添加一个互斥锁,以使底层数据在C++中被更改或者在QML中被更改时不会被同时更改。