基于QGraphicsView的图像显示控件,支持放大、缩小、鼠标拖动

本文主要是介绍基于QGraphicsView的图像显示控件,支持放大、缩小、鼠标拖动,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

原链接

前言

这是一个Qt平台的基于QGraphicsView类的图像显示控件,支持输入QPixmap、QImage、opencv的从cv::Mat类。
实现平台:Windows 10 x64 + Qt 6.2.3 + MSVC 2019 + opencv 4.5

先来看演示视频

控件类实现

ImageViewer.h文件

#ifndef IMAGEVIEWER_H
#define IMAGEVIEWER_H#include <QObject>
#include <QGraphicsItem>
#include <QGraphicsView>
#include <QMouseEvent>
#include <QImage>
#include <QWheelEvent>
#include <QGraphicsScene>
#include "opencv2/opencv.hpp"class ImageViewer : public QGraphicsView
{Q_OBJECT
public:explicit ImageViewer(QWidget *parent = nullptr);signals:public:void setQImage(QImage);void setMatImage(cv::Mat );void setPixmap(QPixmap);void resetImage();QImage getQImage();cv::Mat getMatImage();QPixmap getPixmap();protected:virtual void wheelEvent(QWheelEvent *event) override;virtual void keyPressEvent(QKeyEvent *event) override;virtual void mousePressEvent(QMouseEvent *event) override;virtual void mouseMoveEvent(QMouseEvent *event) override;virtual void mouseReleaseEvent(QMouseEvent *event) override;void zoom(QPoint factor);void togglePan(bool pan, const QPoint &startPos = QPoint());void pan(const QPoint &panTo);void initShow();private:QPixmap m_image;bool m_isPan;QPoint m_prevPan;QGraphicsScene *scene;};#endif // IMAGEVIEWER_H

ImageViewer.cpp 文件

#include "imageviewer.h"
#include <QScrollBar>ImageViewer::ImageViewer(QWidget *parent): QGraphicsView{parent},m_isPan(false),m_prevPan(0,0),scene(nullptr)
{scene = new QGraphicsScene(this);this->setScene(scene);setDragMode(QGraphicsView::DragMode::NoDrag);setInteractive(false);setEnabled(false);
}
QImage cvMatToQImage(cv::Mat &src)
{if(src.channels() == 1) { // if grayscale imagereturn QImage((uchar*)src.data, src.cols, src.rows, static_cast<int>(src.step), QImage::Format_Grayscale8).copy();}if(src.channels() == 3) { // if 3 channel color imagecv::Mat rgbMat;cv::cvtColor(src, rgbMat, cv::COLOR_BGR2RGB); // invert BGR to RGBreturn QImage((uchar*)rgbMat.data, src.cols, src.rows, static_cast<int>(src.step), QImage::Format_RGB888).copy();}return QImage();
}//将QImage转化为Mat
cv::Mat qImageToCvMat( const QImage &inImage)
{switch (inImage.format()){case QImage::Format_RGB32:case QImage::Format_RGB888:{QImage   swapped = inImage;if ( inImage.format() == QImage::Format_RGB32 ){swapped = swapped.convertToFormat( QImage::Format_RGB888 );}cv::Mat matImg = cv::Mat(swapped.height(), swapped.width(),CV_8UC3,const_cast<uchar*>(swapped.bits()),static_cast<size_t>(swapped.bytesPerLine()));cv::cvtColor(matImg,matImg,cv::COLOR_RGB2BGR);return matImg.clone();}case QImage::Format_Indexed8:{cv::Mat  mat( inImage.height(), inImage.width(),CV_8UC1,const_cast<uchar*>(inImage.bits()),static_cast<size_t>(inImage.bytesPerLine()));return mat.clone();}default:break;}return cv::Mat();
}void ImageViewer::setQImage(QImage image)
{   if(image.isNull())return;m_image = QPixmap::fromImage(image);initShow();
}
void ImageViewer::setMatImage(cv::Mat src)
{if(src.empty())return;m_image = QPixmap::fromImage(cvMatToQImage(src));initShow();
}
void ImageViewer::setPixmap(QPixmap pixmap)
{m_image = pixmap.copy();initShow();
}
void ImageViewer::resetImage()
{if(m_image.isNull())return;scene->clear();setEnabled(false);
}
QImage  ImageViewer::getQImage()
{return m_image.toImage();
}
cv::Mat ImageViewer::getMatImage()
{return qImageToCvMat(m_image.toImage());
}
QPixmap ImageViewer::getPixmap()
{return m_image;
}
void ImageViewer::initShow()
{setEnabled(true);setMouseTracking(true);scene->clear();scene->addPixmap(m_image);scene->update();this->resetTransform();this->setSceneRect(m_image.rect());this->fitInView(QRect(0, 0, m_image.width(), m_image.height()), Qt::KeepAspectRatio);
}
void ImageViewer::mousePressEvent(QMouseEvent *event)
{if(event->button() == Qt::LeftButton){togglePan(true, event->pos());event->accept();return;}event->ignore();
}void ImageViewer::mouseMoveEvent(QMouseEvent *event)
{if(m_isPan) {pan(event->pos());event->accept();return;}event->ignore();
}void ImageViewer::mouseReleaseEvent(QMouseEvent *event)
{if(event->button() == Qt::LeftButton){togglePan(false);event->accept();return;}event->ignore();
}void ImageViewer::zoom(QPoint factor)
{QRectF FOV = this->mapToScene(this->rect()).boundingRect();QRectF FOVImage = QRectF(FOV.left(), FOV.top(), FOV.width(), FOV.height());float scaleX = static_cast<float>(m_image.width()) / FOVImage.width();float scaleY = static_cast<float>(m_image.height()) / FOVImage.height();float minScale = scaleX > scaleY ? scaleY : scaleX;float maxScale = scaleX > scaleY ? scaleX : scaleY;if ((factor.y() > 0 && minScale > 100) || (factor.y() < 0 && maxScale < 1 )) {return;}if(factor.y()>0)scale(1.2, 1.2);elsescale(0.8, 0.8);
}
void ImageViewer::keyPressEvent(QKeyEvent *event)
{if(event->key() == Qt::Key_O) {this->resetTransform();this->setSceneRect(m_image.rect());this->fitInView(QRect(0, 0, m_image.width(), m_image.height()), Qt::KeepAspectRatio);}
}void ImageViewer::pan(const QPoint &panTo)
{auto hBar = horizontalScrollBar();auto vBar = verticalScrollBar();auto delta = panTo - m_prevPan;m_prevPan = panTo;hBar->setValue(hBar->value() - delta.x());vBar->setValue(vBar->value() - delta.y());
}void ImageViewer::wheelEvent(QWheelEvent *event)
{if(m_image.isNull())return;QPoint numDegrees = event->angleDelta() / 8;if (!numDegrees.isNull()) {QPoint numSteps = numDegrees / 15;zoom(numSteps);}event->accept();
}void ImageViewer::togglePan(bool pan, const QPoint &startPos)
{if(pan){if(m_isPan) {return;}m_isPan = true;m_prevPan = startPos;setCursor(Qt::ClosedHandCursor);} else {if(!m_isPan) {return;}m_isPan = false;m_prevPan = QPoint(0,0);setCursor(Qt::ArrowCursor);}
}

控件类的使用

具体使用代码如下
1、初始化类对象,并加入界面布局中

	//初始化图片浏览控件,并添加到布局m_view = new ImageViewer(this);//在界面的一个布局中加入控件ui->horizontalLayout_3->addWidget(m_view);

2、打开图像,并加载到控件中

QString filename = getFilePath(QDir::currentPath(),this);qDebug() << filename;if(filename == "")return;//读取为QPixmapQPixmap mapImg(filename);m_view->setPixmap(mapImg);//读取为QImage
//    QImage img(filename);
//    m_view->setQImage(img);//读取为cv::Mat
//    cv::Mat matImg = cv::imread(filename.toLocal8Bit().data(),cv::IMREAD_UNCHANGED);
//    m_view->setMatImage(matImg);

 3、从控件中卸载图片

m_view->resetImage();

如果还是看不懂、建议直接下载源代码

源码链接:https://download.csdn.net/download/xiaohuihuihuige/87239431

这篇关于基于QGraphicsView的图像显示控件,支持放大、缩小、鼠标拖动的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



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

相关文章

SpringKafka消息发布之KafkaTemplate与事务支持功能

《SpringKafka消息发布之KafkaTemplate与事务支持功能》通过本文介绍的基本用法、序列化选项、事务支持、错误处理和性能优化技术,开发者可以构建高效可靠的Kafka消息发布系统,事务支... 目录引言一、KafkaTemplate基础二、消息序列化三、事务支持机制四、错误处理与重试五、性能优

Linux虚拟机不显示IP地址的解决方法(亲测有效)

《Linux虚拟机不显示IP地址的解决方法(亲测有效)》本文主要介绍了通过VMware新装的Linux系统没有IP地址的解决方法,主要步骤包括:关闭虚拟机、打开VM虚拟网络编辑器、还原VMnet8或修... 目录前言步骤0.问题情况1.关闭虚拟机2.China编程打开VM虚拟网络编辑器3.1 方法一:点击还原VM

一文教你解决Python不支持中文路径的问题

《一文教你解决Python不支持中文路径的问题》Python是一种广泛使用的高级编程语言,然而在处理包含中文字符的文件路径时,Python有时会表现出一些不友好的行为,下面小编就来为大家介绍一下具体的... 目录问题背景解决方案1. 设置正确的文件编码2. 使用pathlib模块3. 转换路径为Unicod

CSS模拟 html 的 title 属性(鼠标悬浮显示提示文字效果)

《CSS模拟html的title属性(鼠标悬浮显示提示文字效果)》:本文主要介绍了如何使用CSS模拟HTML的title属性,通过鼠标悬浮显示提示文字效果,通过设置`.tipBox`和`.tipBox.tipContent`的样式,实现了提示内容的隐藏和显示,详细内容请阅读本文,希望能对你有所帮助... 效

使用Python开发一个图像标注与OCR识别工具

《使用Python开发一个图像标注与OCR识别工具》:本文主要介绍一个使用Python开发的工具,允许用户在图像上进行矩形标注,使用OCR对标注区域进行文本识别,并将结果保存为Excel文件,感兴... 目录项目简介1. 图像加载与显示2. 矩形标注3. OCR识别4. 标注的保存与加载5. 裁剪与重置图像

定价129元!支持双频 Wi-Fi 5的华为AX1路由器发布

《定价129元!支持双频Wi-Fi5的华为AX1路由器发布》华为上周推出了其最新的入门级Wi-Fi5路由器——华为路由AX1,建议零售价129元,这款路由器配置如何?详细请看下文介... 华为 Wi-Fi 5 路由 AX1 已正式开售,新品支持双频 1200 兆、配有四个千兆网口、提供可视化智能诊断功能,建

如何设置vim永久显示行号

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

基于WinForm+Halcon实现图像缩放与交互功能

《基于WinForm+Halcon实现图像缩放与交互功能》本文主要讲述在WinForm中结合Halcon实现图像缩放、平移及实时显示灰度值等交互功能,包括初始化窗口的不同方式,以及通过特定事件添加相应... 目录前言初始化窗口添加图像缩放功能添加图像平移功能添加实时显示灰度值功能示例代码总结最后前言本文将

C#实现WinForm控件焦点的获取与失去

《C#实现WinForm控件焦点的获取与失去》在一个数据输入表单中,当用户从一个文本框切换到另一个文本框时,需要准确地判断焦点的转移,以便进行数据验证、提示信息显示等操作,本文将探讨Winform控件... 目录前言获取焦点改变TabIndex属性值调用Focus方法失去焦点总结最后前言在一个数据输入表单

电脑显示hdmi无信号怎么办? 电脑显示器无信号的终极解决指南

《电脑显示hdmi无信号怎么办?电脑显示器无信号的终极解决指南》HDMI无信号的问题却让人头疼不已,遇到这种情况该怎么办?针对这种情况,我们可以采取一系列步骤来逐一排查并解决问题,以下是详细的方法... 无论你是试图为笔记本电脑设置多个显示器还是使用外部显示器,都可能会弹出“无HDMI信号”错误。此消息可能