【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利用PIL进行图片压缩

《Python利用PIL进行图片压缩》有时在发送一些文件如PPT、Word时,由于文件中的图片太大,导致文件也太大,无法发送,所以本文为大家介绍了Python中图片压缩的方法,需要的可以参考下... 有时在发送一些文件如PPT、Word时,由于文件中的图片太大,导致文件也太大,无法发送,所有可以对文件中的图

java获取图片的大小、宽度、高度方式

《java获取图片的大小、宽度、高度方式》文章介绍了如何将File对象转换为MultipartFile对象的过程,并分享了个人经验,希望能为读者提供参考... 目China编程录Java获取图片的大小、宽度、高度File对象(该对象里面是图片)MultipartFile对象(该对象里面是图片)总结java获取图片

Java实战之自助进行多张图片合成拼接

《Java实战之自助进行多张图片合成拼接》在当今数字化时代,图像处理技术在各个领域都发挥着至关重要的作用,本文为大家详细介绍了如何使用Java实现多张图片合成拼接,需要的可以了解下... 目录前言一、图片合成需求描述二、图片合成设计与实现1、编程语言2、基础数据准备3、图片合成流程4、图片合成实现三、总结前

使用Python实现图片和base64转换工具

《使用Python实现图片和base64转换工具》这篇文章主要为大家详细介绍了如何使用Python中的base64模块编写一个工具,可以实现图片和Base64编码之间的转换,感兴趣的小伙伴可以了解下... 简介使用python的base64模块来实现图片和Base64编码之间的转换。可以将图片转换为Bas

css实现图片旋转功能

《css实现图片旋转功能》:本文主要介绍了四种CSS变换效果:图片旋转90度、水平翻转、垂直翻转,并附带了相应的代码示例,详细内容请阅读本文,希望能对你有所帮助... 一 css实现图片旋转90度.icon{ -moz-transform:rotate(-90deg); -webkit-transfo

C#实现添加/替换/提取或删除Excel中的图片

《C#实现添加/替换/提取或删除Excel中的图片》在Excel中插入与数据相关的图片,能将关键数据或信息以更直观的方式呈现出来,使文档更加美观,下面我们来看看如何在C#中实现添加/替换/提取或删除E... 在Excandroidel中插入与数据相关的图片,能将关键数据或信息以更直观的方式呈现出来,使文档更

如何设置vim永久显示行号

《如何设置vim永久显示行号》在Linux环境下,vim默认不显示行号,这在程序编译出错时定位错误语句非常不便,通过修改vim配置文件vimrc,可以在每次打开vim时永久显示行号... 目录设置vim永久显示行号1.临时显示行号2.永www.chinasem.cn久显示行号总结设置vim永久显示行号在li

C#中图片如何自适应pictureBox大小

《C#中图片如何自适应pictureBox大小》文章描述了如何在C#中实现图片自适应pictureBox大小,并展示修改前后的效果,修改步骤包括两步,作者分享了个人经验,希望对大家有所帮助... 目录C#图片自适应pictureBox大小编程修改步骤总结C#图片自适应pictureBox大小上图中“z轴

使用Python将长图片分割为若干张小图片

《使用Python将长图片分割为若干张小图片》这篇文章主要为大家详细介绍了如何使用Python将长图片分割为若干张小图片,文中的示例代码讲解详细,感兴趣的小伙伴可以跟随小编一起学习一下... 目录1. python需求的任务2. Python代码的实现3. 代码修改的位置4. 运行结果1. Python需求

基于Qt Qml实现时间轴组件

《基于QtQml实现时间轴组件》时间轴组件是现代用户界面中常见的元素,用于按时间顺序展示事件,本文主要为大家详细介绍了如何使用Qml实现一个简单的时间轴组件,需要的可以参考下... 目录写在前面效果图组件概述实现细节1. 组件结构2. 属性定义3. 数据模型4. 事件项的添加和排序5. 事件项的渲染如何使用