【QML】用 Image(QQuickPaintedItem) 显示图片

2024-06-24 06:28

本文主要是介绍【QML】用 Image(QQuickPaintedItem) 显示图片,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

  1. 大体功能:
  • 频繁地往界面推送图片,帧率达到视频效果。
  • 捕获画布上的鼠标事件和键盘事件。
  1. 代码如下:
// DrawImageInQQuickPaintedItem.pro 代码如下:
QT += quick# You can make your code fail to compile if it uses deprecated APIs.
# In order to do so, uncomment the following line.
#DEFINES += QT_DISABLE_DEPRECATED_BEFORE=0x060000    # disables all the APIs deprecated before Qt 6.0.0SOURCES += \drawimagectrl.cpp \imagepainter.cpp \main.cppRESOURCES += qml.qrc# Additional import path used to resolve QML modules in Qt Creator's code model
QML_IMPORT_PATH =# Additional import path used to resolve QML modules just for Qt Quick Designer
QML_DESIGNER_IMPORT_PATH =# Default rules for deployment.
qnx: target.path = /tmp/$${TARGET}/bin
else: unix:!android: target.path = /opt/$${TARGET}/bin
!isEmpty(target.path): INSTALLS += targetHEADERS += \drawimagectrl.h \imagepainter.hLIBS += -lopencv_core \-lopencv_imgcodecs// imagepainter.h 代码如下:
#ifndef IMAGEPAINTER_H
#define IMAGEPAINTER_H#include <QQuickPaintedItem>
#include <QImage>#define QML_WRITABLE_PROPERTY(type, name) \protected: \Q_PROPERTY (type name READ get_##name WRITE set_##name NOTIFY name##Changed) \type m_##name; \public: \type get_##name () const { \return m_##name ; \} \public Q_SLOTS: \bool set_##name (type name) { \bool ret = false; \if ((ret = m_##name != name)) { \m_##name = name; \emit name##Changed (m_##name); \} \return ret; \} \Q_SIGNALS: \void name##Changed (type name); \private:class MyQImage : public QObject
{Q_OBJECT
public:explicit MyQImage(QObject *parent = nullptr) : QObject(parent) {}~MyQImage() = default;void setImage(const QImage &img) { m_img = img; }const QImage &getImage() const { return m_img; }private:QImage m_img;
};class ImagePainter : public QQuickPaintedItem
{Q_OBJECTQML_WRITABLE_PROPERTY(MyQImage*, pImage)QML_WRITABLE_PROPERTY(int, nFillMode)public:explicit ImagePainter(QQuickItem *parent = nullptr);void paint(QPainter *painter) override;
};#endif // IMAGEPAINTER_H// imagepainter.cpp 代码如下:
#include "imagepainter.h"
#include <QPainter>ImagePainter::ImagePainter(QQuickItem *parent): QQuickPaintedItem(parent), m_pImage(nullptr), m_nFillMode(0)
{connect(this, &ImagePainter::pImageChanged,[this]{if(m_pImage) {setImplicitWidth(m_pImage->getImage().width());setImplicitHeight(m_pImage->getImage().height());}else {setImplicitWidth(0);setImplicitHeight(0);}update();});
}void ImagePainter::paint(QPainter *painter)
{if(m_pImage) {const QImage &image = m_pImage->getImage();if (image.isNull()) {return;}switch (m_nFillMode) {case 1 /* PreserveAspectFit */: {QImage scaledImage = image.scaled(width(), height(), Qt::KeepAspectRatio);double x = (width() - scaledImage.width()) / 2;double y = (height() - scaledImage.height()) / 2;painter->drawImage(QPoint(x, y), scaledImage);break;}case 0 /* Stretch */:default: {painter->drawImage(QPoint(0, 0), image.scaled(width(), height()));}}}
}// drawimagectrl.h 代码如下:
#ifndef DRAWIMAGECTRL_H
#define DRAWIMAGECTRL_H#include <QObject>
#include "opencv2/opencv.hpp"
#include "imagepainter.h"#define SINGLETON(x)     \
private: \x(x const&); \void operator=(x const&); \
public: \
static x* getInstance(QObject *parent = 0) \
{ \static bool first=true; \if ((parent == 0) && (first == true)) { qCritical("Incorrect Initialisation - no parent and first"); } \if ((parent != 0) && (first == false)) { qCritical("Incorrect Initialisation - parent and not first"); } \first = false; \static x *instance = new x(parent); \return instance; \
} \
private:#define QML_CONSTANT_PROPERTY(type, name) \protected: \Q_PROPERTY (type name READ get_##name CONSTANT) \type m_##name; \public: \type get_##name () const { \return m_##name ; \} \private:class DrawImageCtrl : public QObject
{Q_OBJECTSINGLETON(DrawImageCtrl)QML_CONSTANT_PROPERTY(MyQImage*, pSceneImage)public:explicit DrawImageCtrl(QObject *parent = nullptr);~DrawImageCtrl();public slots:void sltTestDrawImage();// 辅助事件void sltWindowWidthChanged(qreal lfWindowWidth);void sltWindowHeightChanged(qreal lfWindowHeight);// 鼠标事件void sltMousePressed(qreal lfX, qreal lfY, quint32 nButtonValue);void sltMouseReleased(qreal lfX, qreal lfY, quint32 nButtonValue);// 键盘事件void sltKeyPressed(int nKey);void sltKeyReleased(int nKey);signals:void sigImageUpdate();private:void showImage(const cv::Mat &mat);private:// 界面属性qreal m_lfWindowWidth;qreal m_lfWindowHeight;double m_lfLastMouseX;double m_lfLastMouseY;// 快照属性double m_lfZoomFactor;double m_lfImgX;double m_lfImgY;
};#endif // DRAWIMAGECTRL_H// drawimagectrl.cpp 代码如下:
#include "drawimagectrl.h"
#include <QTimer>
#include <QDebug>DrawImageCtrl::DrawImageCtrl(QObject *parent): QObject(parent), m_pSceneImage(new MyQImage(this)), m_lfWindowWidth(0.0), m_lfWindowHeight(0.0), m_lfLastMouseX(-1), m_lfLastMouseY(-1), m_lfZoomFactor(1.0), m_lfImgX(0.0), m_lfImgY(0.0)
{}DrawImageCtrl::~DrawImageCtrl()
{if(nullptr != m_pSceneImage){delete m_pSceneImage;m_pSceneImage = nullptr;}
}void DrawImageCtrl::sltTestDrawImage()
{static int i = 0;QString sPicFileName = QString::fromUtf8("/home/xiaohuamao/mycode/DrawImageInQQuickPaintedItem/TestPic/%1.png").arg(i);if(++i >= 100)i = 0;cv::Mat image = cv::imread(sPicFileName.toStdString());showImage(image);QTimer::singleShot(10, this, &DrawImageCtrl::sltTestDrawImage);
}void DrawImageCtrl::sltWindowWidthChanged(qreal lfWindowWidth)
{m_lfWindowWidth = lfWindowWidth;
}void DrawImageCtrl::sltWindowHeightChanged(qreal lfWindowHeight)
{m_lfWindowHeight = lfWindowHeight;
}void DrawImageCtrl::sltMousePressed(qreal lfX, qreal lfY, quint32 nButtonValue)
{qDebug() << QString::fromUtf8("sltMousePressed x:%1,y:%2,btn:%3").arg(lfX).arg(lfY).arg(nButtonValue);
}void DrawImageCtrl::sltMouseReleased(qreal lfX, qreal lfY, quint32 nButtonValue)
{qDebug() << QString::fromUtf8("sltMouseReleased x:%1,y:%2,btn:%3").arg(lfX).arg(lfY).arg(nButtonValue);
}void DrawImageCtrl::sltKeyPressed(int nKey)
{qDebug() << QString::fromUtf8("sltKeyPressed nKey:%1").arg(nKey);
}void DrawImageCtrl::sltKeyReleased(int nKey)
{qDebug() << QString::fromUtf8("sltKeyReleased nKey:%1").arg(nKey);
}QImage cvMatToQImage( const cv::Mat &inMat )
{switch ( inMat.type() ){// 8-bit, 4 channelcase CV_8UC4:{QImage image( inMat.data,inMat.cols, inMat.rows,static_cast<int>(inMat.step),QImage::Format_ARGB32 );return image;}// 8-bit, 3 channelcase CV_8UC3:{QImage image( inMat.data,inMat.cols, inMat.rows,static_cast<int>(inMat.step),QImage::Format_RGB888 );return image.rgbSwapped();}// 8-bit, 1 channelcase CV_8UC1:{
#if QT_VERSION >= QT_VERSION_CHECK(5, 5, 0)QImage image( inMat.data,inMat.cols, inMat.rows,static_cast<int>(inMat.step),QImage::Format_Grayscale8 );
#elsestatic QVector<QRgb>  sColorTable;// only create our color table the first timeif ( sColorTable.isEmpty() ){sColorTable.resize( 256 );for ( int i = 0; i < 256; ++i ){sColorTable[i] = qRgb( i, i, i );}}QImage image( inMat.data,inMat.cols, inMat.rows,static_cast<int>(inMat.step),QImage::Format_Indexed8 );image.setColorTable( sColorTable );
#endifreturn image;}default:qWarning() << "cvMatToQImage() - cv::Mat image type not handled in switch:" << inMat.type();break;}return QImage();
}void DrawImageCtrl::showImage(const cv::Mat &mat)
{cv::Mat image = mat.clone();m_pSceneImage->setImage(cvMatToQImage(mat));auto lfAspectRatio = 1. * image.cols / image.rows;auto lfAspectRatio2 = 1. * m_lfWindowWidth / m_lfWindowHeight;auto lfFactor = 1.0;if (lfAspectRatio > lfAspectRatio2)lfFactor = 1. * m_lfWindowWidth / image.cols;elselfFactor = 1. * m_lfWindowHeight / image.rows;double lfImgX = (m_lfWindowWidth / lfFactor - image.cols) / 2;double lfImgY = (m_lfWindowHeight / lfFactor - image.rows) / 2;emit sigImageUpdate();m_lfZoomFactor = lfFactor;m_lfImgX = lfImgX;m_lfImgY = lfImgY;
}// main.cpp 代码如下:
#include <QGuiApplication>
#include <QQmlApplicationEngine>
#include <QQmlContext>
#include "drawimagectrl.h"
#include "imagepainter.h"void initDrawImage(QQmlApplicationEngine &engine)
{qmlRegisterType<ImagePainter>("MyItem", 1, 0, "ImagePainter");engine.rootContext()->setContextProperty(QLatin1String("drawImageCtrl"), DrawImageCtrl::getInstance());
}int main(int argc, char *argv[])
{
#if QT_VERSION < QT_VERSION_CHECK(6, 0, 0)QCoreApplication::setAttribute(Qt::AA_EnableHighDpiScaling);
#endifQGuiApplication app(argc, argv);QQmlApplicationEngine engine;const QUrl url(QStringLiteral("qrc:/main.qml"));QObject::connect(&engine, &QQmlApplicationEngine::objectCreated,&app, [url](QObject *obj, const QUrl &objUrl) {if (!obj && url == objUrl)QCoreApplication::exit(-1);}, Qt::QueuedConnection);initDrawImage(engine);engine.load(url);return app.exec();
}// main.qml 代码如下:
import QtQuick 2.15
import QtQuick.Window 2.15
import QtQuick.Controls 2.15Window {width: 640height: 480visible: truetitle: qsTr("Hello World")DrawImage {anchors.fill: parent}Button {text: "draw"onClicked: {drawImageCtrl.sltTestDrawImage();}}
}// DrawImage.qml 代码如下:
import QtQuick 2.0
import MyItem 1.0Rectangle {id : canvasRectConnections{target: drawImageCtrlfunction onSigImageUpdate(){idSceneImage.update();}}Image {id: imgCanvaswidth: parent.widthheight: parent.heightanchors.fill: parentImagePainter {id: idSceneImageanchors.fill: parentnFillMode: Image.PreserveAspectFitpImage: drawImageCtrl.pSceneImagevisible: true}MouseArea {anchors.fill: parenthoverEnabled: truepropagateComposedEvents: trueacceptedButtons: Qt.LeftButton | Qt.RightButton | Qt.MidButtononEntered: {imgCanvas.forceActiveFocus();}onPressed: {drawImageCtrl.sltMousePressed(mouse.x, mouse.y, mouse.button);}onReleased: {drawImageCtrl.sltMouseReleased(mouse.x, mouse.y, mouse.button);}}Keys.onPressed: {drawImageCtrl.sltKeyPressed(event.key);}Keys.onReleased: {drawImageCtrl.sltKeyReleased(event.key);}onWidthChanged: {drawImageCtrl.sltWindowWidthChanged(imgCanvas.width);}onHeightChanged: {drawImageCtrl.sltWindowHeightChanged(imgCanvas.height);}}onVisibleChanged: {if(canvasRect.visible) {imgCanvas.focus = true;}else {imgCanvas.focus = false;}}onFocusChanged: {if(canvasRect.focus)imgCanvas.focus = true;}
}

这篇关于【QML】用 Image(QQuickPaintedItem) 显示图片的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/1089415

相关文章

Python实现精准提取 PDF中的文本,表格与图片

《Python实现精准提取PDF中的文本,表格与图片》在实际的系统开发中,处理PDF文件不仅限于读取整页文本,还有提取文档中的表格数据,图片或特定区域的内容,下面我们来看看如何使用Python实... 目录安装 python 库提取 PDF 文本内容:获取整页文本与指定区域内容获取页面上的所有文本内容获取

Python基于微信OCR引擎实现高效图片文字识别

《Python基于微信OCR引擎实现高效图片文字识别》这篇文章主要为大家详细介绍了一款基于微信OCR引擎的图片文字识别桌面应用开发全过程,可以实现从图片拖拽识别到文字提取,感兴趣的小伙伴可以跟随小编一... 目录一、项目概述1.1 开发背景1.2 技术选型1.3 核心优势二、功能详解2.1 核心功能模块2.

Go语言如何判断两张图片的相似度

《Go语言如何判断两张图片的相似度》这篇文章主要为大家详细介绍了Go语言如何中实现判断两张图片的相似度的两种方法,文中的示例代码讲解详细,感兴趣的小伙伴可以跟随小编一起学习一下... 在介绍技术细节前,我们先来看看图片对比在哪些场景下可以用得到:图片去重:自动删除重复图片,为存储空间"瘦身"。想象你是一个

使用Python实现base64字符串与图片互转的详细步骤

《使用Python实现base64字符串与图片互转的详细步骤》要将一个Base64编码的字符串转换为图片文件并保存下来,可以使用Python的base64模块来实现,这一过程包括解码Base64字符串... 目录1. 图片编码为 Base64 字符串2. Base64 字符串解码为图片文件3. 示例使用注意

RedisTemplate默认序列化方式显示中文乱码的解决

《RedisTemplate默认序列化方式显示中文乱码的解决》本文主要介绍了SpringDataRedis默认使用JdkSerializationRedisSerializer导致数据乱码,文中通过示... 目录1. 问题原因2. 解决方案3. 配置类示例4. 配置说明5. 使用示例6. 验证存储结果7.

c/c++的opencv实现图片膨胀

《c/c++的opencv实现图片膨胀》图像膨胀是形态学操作,通过结构元素扩张亮区填充孔洞、连接断开部分、加粗物体,OpenCV的cv::dilate函数实现该操作,本文就来介绍一下opencv图片... 目录什么是图像膨胀?结构元素 (KerChina编程nel)OpenCV 中的 cv::dilate() 函

使用Python实现调用API获取图片存储到本地的方法

《使用Python实现调用API获取图片存储到本地的方法》开发一个自动化工具,用于从JSON数据源中提取图像ID,通过调用指定API获取未经压缩的原始图像文件,并确保下载结果与Postman等工具直接... 目录使用python实现调用API获取图片存储到本地1、项目概述2、核心功能3、环境准备4、代码实现

idea中project的显示问题及解决

《idea中project的显示问题及解决》:本文主要介绍idea中project的显示问题及解决方案,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教... 目录idea中project的显示问题清除配置重China编程新生成配置总结idea中project的显示问题新建空的pr

Java实现图片淡入淡出效果

《Java实现图片淡入淡出效果》在现代图形用户界面和游戏开发中,**图片淡入淡出(FadeIn/Out)**是一种常见且实用的视觉过渡效果,它可以用于启动画面、场景切换、轮播图、提示框弹出等场景,通过... 目录1. 项目背景详细介绍2. 项目需求详细介绍2.1 功能需求2.2 非功能需求3. 相关技术详细

Java如何根据文件名前缀自动分组图片文件

《Java如何根据文件名前缀自动分组图片文件》一大堆文件(比如图片)堆在一个目录下,它们的命名规则遵循一定的格式,混在一起很难管理,所以本文小编就和大家介绍一下如何使用Java根据文件名前缀自动分组图... 目录需求背景分析思路实现代码输出结果知识扩展需求一大堆文件(比如图片)堆在一个目录下,它们的命名规