【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;}
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/web/32864.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

常说的云VR是什么意思?与传统vr的区别

虚拟现实&#xff08;Virtual Reality&#xff0c;简称VR&#xff09;是一种利用计算机技术模拟产生一个三维空间的虚拟世界&#xff0c;让用户通过视觉、听觉、触觉等感官&#xff0c;获得与现实世界类似或超越的体验。VR技术发展历程可追溯至上世纪&#xff0c;经历概念提出、…

某大厂程序员吐槽:离职交接时,新人被工作量吓退,领导却污蔑我故意劝退新人,我怒晒工作短信反击证明,新人看了后也决定走人了!

一位知名大公司的程序员分享了他离职时的遭遇&#xff1a;在交接工作时&#xff0c;新进的同事因工作量过大而感到压力&#xff0c;但出乎意料的是&#xff0c;他们的领导却指责我故意吓唬新人。为了证明自己的清白&#xff0c;我晒出了工作短信作为反击&#xff0c;结果连新人…

Linux系统编程--软/硬连接

真正找到磁盘上文件的并不是文件名&#xff0c;而是inode。 其实在linux中可以让多个文件名对应于同一个inode。 命令&#xff1a; 软连接&#xff1a;ln -s 原文件名 新文件名 硬链接&#xff1a;ln 原文件名 新文件名 删除链接文件&#xff1a;unlink 文件名执行上面两条命令…

matplotlib之常见图像种类

Matplotlib 是一个用于绘制图表和数据可视化的 Python 库。它支持多种不同类型的图形&#xff0c;以满足各种数据可视化需求。以下是一些 Matplotlib 支持的主要图形种类&#xff1a; 折线图&#xff08;Line Plot&#xff09;&#xff1a; 用于显示数据随时间或其他连续变量的…

Git使用过程中涉及的几个区域

一. 简介 Git 是一个开源的分布式版本控制系统&#xff0c;可以有效、高速的处理从很小到非常大的项目版本管理&#xff0c;也是 Linus Torvalds 为了帮助管理 Linux内核开发而开发的一个开放源码的版本控制软件。 本文简单了解一下 git涉及的几个部分&#xff0c;以及git 常…

vue登陆密码加密,java后端解密

前端 安装crypto-js npm install crypto-js加密 //引入crypto-js import CryptoJS from crypto-js;/** ---密码加密 start--- */ const SECRET_KEY CryptoJS.enc.Utf8.parse("a15q8f6s5s1a2v3s"); const SECRET_IV CryptoJS.enc.Utf8.parse("a3c6g5h4v9sss…

基于网络搜索的长篇问答能力优化:FoRAG

检索增强生成&#xff08;RAG&#xff0c;Retrieval Augmented Generation&#xff09;可以利用搜索引擎检索技术来提升长篇问答质量&#xff0c;因而在 QA 任务中广受欢迎。尽管有多种开源方法和网络增强的商业系统如 Bing Chat 出现&#xff0c;但生成长篇答案的事实性和逻辑…

ruoyi添加自己的菜单

先把自己自定义的view填写好 在菜单管理模块 因为我已经新增过&#xff0c;所以就看看我填的啥就行了 我发现一个问题&#xff0c;路由地址可以填index2或者scooldemo/index2都可以&#xff08;这个包含了文件夹路径&#xff09;&#xff0c;反正组件路径一定要填对就可以了。 …

【UML用户指南】-21-对基本行为建模-活动图

目录 1、概念 2、组成结构 2.1、动作 2.2、活动节点 2.3、控制流 2.4、分支 2.5、分岔和汇合 2.6、泳道 2.7、对象流 2.8、扩展区域 3、一般用法 3.1、对工作流建模 3.2、对操作建模 一个活动图从本质上说是一个流程图&#xff0c;展现从活动到活动的控制流 活动图…

六套Matlab人脸识别源码 可运行 (含PCA Adaboost DLDA算法等)

以PCA人脸识别为例: 随着社会发展与科技进步,人们对生活和工作环境有了更高的要求。大家对外界的需求不再局限于刚性的满足,追求目标逐渐上升到对家居和办公智能化、自动化的台阶上。与此同时,人脸识别技术越来越广泛的应用于某些重要场所的身份检测和确认环节[1]。在公共…

MySQL命名规范(自用)

MtySQL命名规范 基本通用规范 1.【推荐】关键字必须大写 所有关键字必须大写&#xff0c;如&#xff1a;INSERT、UPDATE、DELETE、SELECT及其子句&#xff0c;IF……ELSE、CASE、DECLARE等 2.【强制】字段和建表必须写备注 COMMENT写备注 3.【强制】字母数字下划线 采用26个英…

国产MCU芯片(2):东软MCU概览及触控MCU

前言: 国产芯片替代的一个主战场之一就是mcu,可以说很多国内芯片设计公司都打算或者已经在设计甚至有了一款或多款的量产产品了,这也是国际大背景决定的。过去的家电市场、过去的汽车电子市场,的确国产芯片的身影不是很常见,如今不同了,很多fabless投身这个行业,一种是…

OpenGL3.3_C++_Windows(18)

接口块&#xff1a; glsl彼此传输数据&#xff0c;通过in / out&#xff0c;当更多的变量&#xff0c;涉及数组和结构体接口块(Interface Block)类似struct&#xff0c;in / out 块名{……}实例名 Uniform缓冲对象&#xff1a; 首先理解uniform Object&#xff1a;负责向gl…

程序人生:关于RHCE红帽认证这件事

花了两个月备考红帽&#xff0c;最终终于双满分通过。 关于考试 RHCE红帽认证总共需要考两门&#xff1a;RHCSA、RHCE。 RHCSA主要是考察基本的Linux操作&#xff1a;用户、权限、空间扩容、yum、容器等内容。 RHCE主要是考察ansible playbook 代码的开发。 通过考试没有别…

【内存管理】页面分配机制

前言 Linux内核中是如何分配出页面的&#xff0c;如果我们站在CPU的角度去看这个问题&#xff0c;CPU能分配出来的页面是以物理页面为单位的。也就是我们计算机中常讲的分页机制。本文就看下Linux内核是如何管理&#xff0c;释放和分配这些物理页面的。 伙伴算法 伙伴系统的…

代码随想录训练营Day32

提示&#xff1a;文章写完后&#xff0c;目录可以自动生成&#xff0c;如何生成可参考右边的帮助文档 文章目录 前言一、买卖股票的最佳时机2二、跳跃游戏三、跳跃游戏2四、K次取反后最大化的数组和 前言 今天是跟着代码随想录刷题的第32天&#xff0c;主要是学了买卖股票的最…

设计模式4-模版方法

设计模式 重构获得模式重构的关键技法1. 静态转动态2. 早绑定转晚绑定3. 继承转组合4. 编译时依赖转运行时依赖5. 紧耦合转松耦合 组件协助动机模式定义结构 要点总结。 例子示例解释&#xff1a; 重构获得模式 设计模式的目的是应对变化&#xff0c;提高复用 设计模式的要点…

[SAP ABAP] 排序内表数据

语法格式 整表排序 SORT <itab> [ASCENDING|DESCENDING]. 按指定字段排序 SORT <itab> BY f1 [ASCENDING|DESCENDING] f2 [ASCENDING|DESCENDING] ... fn [ASCENDING|DESCENDING].<itab>&#xff1a;代表内表 不指定排序方式则默认升序排序 示例1 结果显…

.hmallox勒索病毒解密方法|勒索病毒解决|勒索病毒恢复|数据库修复

导言&#xff1a; 在当今数字化时代&#xff0c;勒索病毒已经成为网络安全的一大威胁&#xff0c;其中包括了最近出现的.hmallox勒索病毒。这类恶意软件不仅能够对计算机系统进行加密&#xff0c;还会要求用户支付赎金以换取解密密钥&#xff0c;给个人用户和企业带来了严重的…

Android SurfaceFlinger——HWC Adapter初始化(五)

上一篇文章对 HWC 硬件加载流程进行了分析,在加载完成后开始创建 HAL 实例时,首先需要对 hwc2_device_t 的适配器进行初始化,这里我们主要分析 HWC Adapter 的创建流程。 一、创建HWC Adapter 在创建 HAL 实例之前,我们先来看一下 HWC Adapter 的创建。 1、createHalWith…