QML学习笔记——图片动态显示(Image与QQuickImageProvider)
程序员文章站
2022-03-09 13:34:25
...
写在前面
- 项目中需要一个预览和回显的功能,需要通过udp接收图片数据,并在界面上动态显示,在网上研究一番后,最终选择了
Image
和QQuickImageProvider
来实现。 - 这里只是记录下关键机制,实际应用场景更复杂,需要拆包并包,考虑超时,掉线,多设备同时预览的效率等问题。
实际使用
环境
- Qt 5.9.3 + MinGW
- window 10
Image
- Image来实现图片的显示,可以显示本地图片和网络图片。
Image {
id: img_preview;
width: 170;
height: 100;
source: "qrc:/bord/img/block.jpg"; //加载资源文件
//source: "file:///E:/bord/img/block.jpg"; //加载本地图片
//cache:false; //是否缓存
}
QQuickImageProvider
- The QQuickImageProvider class provides an interface for supporting pixmaps and threaded image requests in QML.
可以将QPixmap
或者QImage
的图片提供给QML进行显示。
具体实现
新建UDP监听线程
建立一个UDP线程单独监听图片数据,这里写的比较简单,假设udp直接发的一包完整jpg图片数据,data_image 为全局变量。mutex_prest为互斥锁(
QMutex
),因为data_image会被其他线程访问(不然程序容易崩溃)。QByteArray data_image
QMutex mutex_prest
我是定义在config.h
里面的,可以根据实际使用自行安排。
void MyThread::run()
{
receiver_udp=new QUdpSocket;
receiver_udp->bind(00000,QUdpSocket::ShareAddress); //绑定需要监听的端口
connect(receiver_udp,SIGNAL(readyRead()),this,SLOT(processPendingDatagram()),Qt::DirectConnection);
exec();
}
void MyThread::processPendingDatagram()
{
while(receiver_udp->hasPendingDatagrams()) //拥有等待的数据报
{
QByteArray datagram;
datagram.resize(receiver_udp->pendingDatagramSize());
receiver_udp->readDatagram(datagram.data(),datagram.size());
mutex_prest.lock(); //加锁
//data_image是全局变量,这边datagram为一张图片的包,实际可能需对数据进行处理
data_image.clear();
data_image = datagram;
mutex_prest.unlock(); //解锁
}
}
继承QQuickImageProvider类
- 头文件
#ifndef MYIMAGEPROVIDER_H
#define MYIMAGEPROVIDER_H
#include <QQuickImageProvider>
//#include <QQuickWindow>
#include <QImage>
class MyImageProvider : public QQuickImageProvider
{
public:
MyImageProvider();
~MyImageProvider();
QImage requestImage(const QString & id, QSize * size, const QSize & requestedSize);
};
#endif // MYIMAGEPROVIDER_H
- cpp
- 利用函数
requestImage(const QString &id, QSize *size, const QSize &requestedSize)
完成图片请求,在多个请求或者多个图片时,可以用 id 变量进行进一步判断。
#include "myimageprovider.h"
#include "config.h"
#include <QImageReader>
#include <QBuffer>
MyImageProvider::MyImageProvider()
: QQuickImageProvider(QQuickImageProvider::Image)
{
}
MyImageProvider::~MyImageProvider()
{
}
QImage MyImageProvider::requestImage(const QString &id, QSize *size, const QSize &requestedSize)
{
//按IP和类型进行处理
//qDebug() << "id: " << id;
//QString type;
//type=id.mid(0,id.indexOf(":"));
//QString str;
//str=id.mid(id.indexOf(":")+1,id.indexOf("/")-id.indexOf(":")-1);
QImage image;
if(data_image.size()!=0)
{
mutex_prest.lock();
//QByteArray 转 QImage
QBuffer buffer(&(data_image.image));
buffer.open(QIODevice::ReadOnly);
QImageReader reader(&buffer,"JPG");
image = reader.read();
mutex_prest.unlock();
}
else
{
//若图片数据为空,则加载默认图片
image.load(":/bord/img/block.jpg");
}
return image;
}
注册MyImageProvider
- 在
main.cpp
中将MyImageProvider
注册到QML中。
MyImageProvider *myImg = new MyImageProvider();
QQmlApplicationEngine engine;
engine.addImageProvider(“MyProvider”, myImg);
engine.load(QUrl(QLatin1String(“qrc:/main.qml”)));
Image动态显示
-
cache
是否缓存,设为false。默认为true - 使用定时器动态刷新,定时时间根据具体接收效率和显示帧率设置。或者也可以采用信号与槽的方式通知刷新。
Image {
id: img_preview
cache: false; //取消缓存
width: 170;
height: 100;
source: "qrc:/bord/img/block.jpg" //默认图片
}
Timer{
//定时器触发时间 单位毫秒
interval: 100;
//触发定时器
running: true;
//不断重复
repeat: true;
//定时器触发时执行
onTriggered: {
img_preview.source = "";
img_preview.source = "image://myprovider/ip:xxx.xxx.xxx.xxx";
}
}
小结
- 当某个变量被多个线程访问时,注意使用
QMutex
来保护访问安全。 - Image在刷新source时,注意先置空,且取消缓存,不然会出现图片刷新无反应的情况,或者使用加随机数的方式
source = "image://myprovider/ip:"+Math.random();
本作品采用知识共享署名-非商业性使用-相同方式共享 4.0 国际许可协议进行许可。
上一篇: JavaScript隐藏元素的方法有哪些