问题描述
我已经浏览了文档以及我可以在互联网上找到的所有内容,但似乎无法从 C++ 访问 QML 图像.
I've looked through the documentation and also whatever I could find on the internet, but it doesn't seem like it is possible to access a QML Image from C++.
有没有办法解决这个问题?
Is there a way to work around that?
推荐答案
在 QtQuick1 中可以实现,但在 QtQuick2 中删除了该功能.
It was possible to do in QtQuick1 but that functionality was removed in QtQuick2.
我提出的解决方案允许在 QML 和 C++ 中使用相同的图像,方法是实现一个 QQuickImageProvider
,它基本上与 QPixmap *
一起使用,它被转换为字符串然后回到指针类型(听起来确实有点不安全,但事实证明它工作得很好).
The solution I've come up with allows to have the same image in QML and C++ by implementing a QQuickImageProvider
that basically works with QPixmap *
which is converted to string and then back to a pointer type(it does sound a little unsafe but has proven to work quite 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;
};
Pixmap
元素的实现非常简单,虽然初始的有点受限,因为新的像素图恰好被分配在与 data
不同图像的字符串相同,导致QML图像组件不更新,但解决方案很简单,只有在分配新像素图后才删除旧像素图.这是实际的图像提供程序:
The implementation of the Pixmap
element is pretty straightforward, although the initial was a bit limited, since the new pixmap happened to be allocated at the exactly same memory address the data
string was the same for different images, causing the QML Image component to not update, but the solution was as simple as deleting the old pixmap only after the new one has been allocated. 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();
}
}
};
注册:
//in main()
engine.addImageProvider("pixmap", new PixmapProvider);
qmlRegisterType<Pixmap>("Test", 1, 0, "Pixmap");
这就是你在 QML 中使用它的方式:
And this is how you use it in QML:
Pixmap {
id: pix
}
Image {
source: pix.data
}
// and then pix.load(path)
还请注意,在我的情况下,没有实际修改需要在 QML 中更新的像素图.如果在 C++ 中更改图像,此解决方案不会自动更新 QML 中的图像,因为内存中的地址将保持不变.但解决方案同样简单——实现一个 update()
方法来分配一个 new QPixmap(oldPixmap)
——它将使用相同的内部数据,但会给你一个具有新内存地址的新访问器,这将触发 QML 图像更新更改.这意味着提供的访问像素图的方法将通过 Pixmap
类,而不是直接从 QPixmap *
中获取,因为您将需要 Pixmap
类要触发 data
更改,只需为 pix
添加一个访问器,以防万一您执行复杂或线程化的操作,您可能需要使用 QImage
而是添加一个互斥锁,以便在 QML 中底层数据在 C++ 中或其他方式中更改时不会更改.
ALSO Note that in my case there was no actual modification of the pixmap that needed to be updated in QML. This solution will not auto-update the image in QML if it is changed in C++, because the address in memory will stay the same. But the solution for this is just as straightforward - implement an update()
method that allocates a new QPixmap(oldPixmap)
- it will use the same internal data but give you a new accessor to it with a new memory address, which will trigger the QML image to update on changes. This means the proffered method to access the pixmap will be through the Pixmap
class, not directly from the QPixmap *
since you will need the Pixmap
class to trigger the data
change, so just add an accessor for pix
, and just in case you do complex or threaded stuff, you might want to use QImage
instead and add a mutex so that the underlying data is not changed in QML while being changed in C++ or the other way around.
这篇关于QML 和 C++ 图像互操作性的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持跟版网!