前言
开发Qt应用时,想把QImage发送到QML端通过Image组件显示出来,这种场景主要用在例如在C++端调用android系统接口截图然后发送到QML端显示,或者C++端QWidget截图然后让QML界面中显示。要想实现该功能,需要用到一个重要的类QQuickImageProvider,这是专门从C++端提供图片到QML显示的。
正文
先来看看Qt的示例
首先定义一个类并继承于QQuickImageProvider,然后重新实现接口requestPixmap,如果需要传入QImage图片的话就重写requestImage接口,原理是一样的,详情查看Qt官方文档。
class ColorImageProvider : public QQuickImageProvider
{
public:
ColorImageProvider()
: QQuickImageProvider(QQuickImageProvider::Pixmap)
{
}
QPixmap requestPixmap(const QString &id, QSize *size, const QSize &requestedSize)
{
int width = 100;
int height = 50;
if (size)
*size = QSize(width, height);
QPixmap pixmap(requestedSize.width() > 0 ? requestedSize.width() : width,
requestedSize.height() > 0 ? requestedSize.height() : height);
pixmap.fill(QColor(id).rgba());
return pixmap;
}
};
然后在main函数中添加图片入口,使用addImageProvider函数
int main(int argc, char *argv[])
{
...
QQuickView view;
QQmlEngine *engine = view.engine();
engine->addImageProvider(QLatin1String("colors"), new ColorPixmapProvider);
...
}
再在QML端界面上显示
Column {
Image { source: "image://colors/yellow" }
Image { source: "image://colors/red" }
}
这里的colors就是main函数中定义的图片文件夹名称,yellow和red相当于id,也就是在requestPixmap中的第一个参数可以拿到这个值。编译运行后,得到如下示意图:
动态刷新图片
以上是显示一张静态图片,如果是要动态的刷新QML的图片要怎么办呢?接着看
class ImageProvider : public QQuickImageProvider
{
public:
ImageProvider();
QImage requestImage(const QString &id, QSize *size, const QSize &requestedSize);
QPixmap requestPixmap(const QString &id, QSize *size, const QSize &requestedSize);
QImage img;
};
#include "imageprovider.h"
ImageProvider::ImageProvider()
: QQuickImageProvider(QQuickImageProvider::Image)
{
}
QImage ImageProvider::requestImage(const QString &id, QSize *size, const QSize &requestedSize)
{
return this->img;
}
QPixmap ImageProvider::requestPixmap(const QString &id, QSize *size, const QSize &requestedSize)
{
return QPixmap::fromImage(this->img);
}
然后再定义一个类
class ShowImage : public QObject
{
Q_OBJECT
public:
explicit ShowImage(QObject *parent = 0);
ImageProvider *m_pImgProvider;
public slots:
void setImage(QImage image);
signals:
void callQmlRefeshImg();
};
ShowImage::ShowImage(QObject *parent) :
QObject(parent)
{
m_pImgProvider = new ImageProvider();
}
void ShowImage::setImage(QImage image)
{
m_pImgProvider->img = image;
emit callQmlRefeshImg();
}
然后在main函数中注册
ShowImage *CodeImage = new ShowImage(this);
engine.rootContext()->setContextProperty("CodeImage",CodeImage);
engine.addImageProvider(QLatin1String("CodeImg"), CodeImage->m_pImgProvider);
回到QML中调用
Image{
id:img
anchors.fill: parent
}
Connections{
target: CodeImage
onCallQmlRefeshImg:{
img.source = ""
img.source = "image://CodeImg"
}
}
注意,这里刷新图片的时候必须先设置为空img.source = “”,否则无法刷新。另外,我在Mac 上用 Qt5.11版本测试的时候,发现图片依然不能刷新,然后在 Image 属性加上一句:cache:false 就搞定了,不显示的原因是 Image 自动做了缓存,把缓存去掉就行了。
这样一来,C++端设置新图片后会发送信号,在QML端连接信号然后去图片目录下去取出来刷新当前控件。原理很简单,不再赘述。
添加了演示代码,在这里