Qt 完成图片的缩放拖动
1. 事件和函数
主要使用事件paintEvent(QPaintEvent *event)和drawTiledPixmap函数实现绘图。
- paintEvent事件在改变窗口大小、移动窗口、手动调用update等情形下会被调用。
- 需先了解下绘图该函数的用法。 - QPainter::drawTiledPixmap(int x, int y, int w, int h, const QPixmap &pm, int sx, int sy)
- 效果:
2. 建立项目
假设已新建了mainwindow项目。现再添加一界面用于单独显示图片,作为子窗口供调用(当然,也可在main.c直接调用,作为父窗口)。
1)右击界面文件—添加新文件—QT—QT设计师界面类—choose—Dialog without buttons。类名为CImgPaint。
打开ui文件,添加控件,主要是label和button,
具体属性列表如下:
其中,label控件仅仅是提供绘图的区域,但最终绘图不是绘在label控件上。
3. 头文件添加变量,编写构造函数
头文件中包含头文件
#define USE_OPENCV 0#include <QDialog>
#include "mainwindow.h"
#include "QPoint"
using namespace std;
#if USE_OPENCV#include "opencv2/opencv.hpp"#include <opencv2/core.hpp>using namespace cv;
#endifnamespace Ui {
class CImgPaint;
}
类中添加成员变量
private:QPixmap pix_src,pix_fix;//原始图片及缩放图片float ratio=1.0; //缩放比QRect paint_rect; //绘画限制区域int paint_xe,paint_ye,paint_we,paint_he;//期望绘画区域int paint_x,paint_y,paint_w,paint_h;//实际绘画区域int pix_sx,pix_sy; //选择图片的起始x、y开始绘画int step_val = 20; //单次移动步长bool mouse_press_flag = false;//鼠标是否按下QPoint mouse_pos_pre,mouse_pos_cur;//记录鼠标位置
构造函数中,添加输入图片的读取,以及变量初始化。
#include "CImgPaint.h"
#include "ui_cimgpaint.h"
#include "QDebug"
#include "QPainter"
#include "QWheelEvent"
#include "QImage"
CImgPaint::CImgPaint(QWidget *parent) :QDialog(parent),ui(new Ui::CImgPaint)
{ui->setupUi(this);#if USE_OPENCVcv::Mat img = cv::imread("lenaGray.jpg",-1);pix_src = get_pixmap_from_mat(img);
#elseQImage qimg ;qimg.load("./lenaGray.jpg");pix_src = pix_src.fromImage(qimg);
#endifpaint_rect.setRect(ui->label_paint->x()+1,ui->label_paint->y()+1,ui->label_paint->width()+1,ui->label_paint->height()+1);pix_fix = pix_src.scaled(paint_rect.width(),paint_rect.height(),Qt::KeepAspectRatio,Qt::FastTransformation);reset_para();update_para();
}void CImgPaint::reset_para(void)
{ratio = 1.0;paint_xe = paint_x =paint_rect.x() ;paint_ye = paint_y = paint_rect.y();paint_we = paint_w = paint_rect.width();paint_he = paint_h = paint_rect.height();pix_sx = 0;pix_sy = 0;
}#if USE_OPENCV
QPixmap CImgPaint::get_pixmap_from_mat(Mat img)
{cv::Mat img_temp = img.clone();QImage::Format format = QImage::Format_RGB888;if(img_temp.channels()==1){format = QImage::Format_Grayscale8;}if(img_temp.channels()==3){cv::cvtColor(img_temp,img_temp,CV_BGR2RGB);//opencv 按BGR处理}if(img_temp.depth()==CV_16U){img_temp.convertTo(img_temp,CV_8U,1.0/257.0);}QPixmap pixmap = QPixmap::fromImage(QImage(img_temp.data,img_temp.cols,img_temp.rows,(int)img_temp.step,format));return pixmap;}
#endif
CImgPaint::~CImgPaint()
{delete ui;
}
update_para函数用来确定drawTiledPixmap函数的各参数。
void CImgPaint::update_para(void)
{//*************** 0. 处理放大和缩小 **********************//// 放大缩小仅仅改变width和height,图像的起始点,不变int w,h;w = ratio*paint_rect.width();//放大或缩小,统一对标到画布尺寸h = ratio*paint_rect.height();pix_fix = pix_src.scaled(w,h,Qt::KeepAspectRatio,Qt::FastTransformation);//对输入的原图进行放大、缩小paint_we = pix_fix.width();//得到初始的图像w、h期望值paint_he = pix_fix.height();//*************** 1. 处理Y方向 **********************////1.1 首先确定实际绘图的起点,绘图的起点应在画布的大小范围内 //// 若期望的起点超出画布上限,则设置截取图像的起始位置sypaint_y = paint_ye;if(paint_y < paint_rect.y()){pix_sy = paint_rect.y() - paint_y;pix_sy = pix_sy>pix_fix.height()?pix_fix.height():pix_sy;paint_y = paint_rect.y();}else{pix_sy = 0;}//若期望的起点超出画布下限,不允许if(paint_y>=(paint_rect.y()+paint_rect.height()-1)){paint_y = (paint_rect.y()+paint_rect.height()-1);}//1.2 再确定终点,即高度//对于图片本身,减去sy,得到图片本身剩余的高度paint_he -= pix_sy;// 图片本身的高度,同样不可超过画图区域剩余的高度paint_he = paint_he>( paint_rect.height()+paint_rect.y()-paint_y )?(paint_rect.height()+paint_rect.y()-paint_y):paint_he;//*************** 2. 处理X方向 **********************////1.1 首先确定实际绘图的起点,绘图的起点应在画布的大小范围内 //// 若期望的起点超出画布上限,则设置截取图像的起始位置sxpaint_x = paint_xe;if(paint_x < paint_rect.x()){pix_sx = paint_rect.x() - paint_x;pix_sx = pix_sx>pix_fix.width()?pix_fix.width():pix_sx;paint_x = paint_rect.x();}else{pix_sx = 0;}//若期望的起点超出画布下限,不允许if(paint_x>=(paint_rect.x()+paint_rect.width()-1)){paint_x = (paint_rect.x()+paint_rect.width()-1);}//1.2 再确定终点,即宽度//对于图片本身,减去sx,得到图片本身剩余的宽度paint_we -= pix_sx;// 图片本身的宽度,同样不可超过画图区域剩余的宽度paint_we = paint_we>( paint_rect.width()+paint_rect.x()-paint_x )?(paint_rect.width()+paint_rect.x()-paint_x):paint_we;paint_h = paint_he;paint_w = paint_we;qDebug()<<paint_rect;qDebug()<<paint_x<<paint_y<<paint_w<<paint_h<<pix_fix<<pix_sx<<pix_sy;}
4. paintEvent事件
头文件声明void paintEvent(QPaintEvent *event);并且在cpp文件中重写该事件函数
public slots:void paintEvent(QPaintEvent *event);
void CImgPaint::paintEvent(QPaintEvent *event)
{QPainter painter(this);painter.setRenderHints(QPainter::SmoothPixmapTransform|QPainter::Antialiasing|QPainter::TextAntialiasing);painter.drawRect(paint_rect.x()-1,paint_rect.y()-1,paint_rect.width()+1,paint_rect.height()+1); //画框painter.drawTiledPixmap(paint_x,paint_y,paint_w,paint_h,pix_fix,pix_sx,pix_sy);//绘图}
5. 编写按钮的回调函数
按钮的回调函数主要用来修改变量的值。修改完后,调用update_para、update,重绘。
update_para函数用来确定drawTiledPixmap函数的各参数。
void CImgPaint::on_pushButton_zoomIn_clicked()
{ratio = ratio + 0.1*ratio;update_para();this->update();
}void CImgPaint::on_pushButton_zoomOut_clicked()
{ratio = ratio - 0.1*ratio;update_para();this->update();
}void CImgPaint::on_pushButton_Up_clicked()
{paint_ye -=step_val;update_para();this->update();
}void CImgPaint::on_pushButton_Down_clicked()
{paint_ye +=step_val;update_para();this->update();}void CImgPaint::on_pushButton_Left_clicked()
{paint_xe -= step_val;update_para();this->update();}void CImgPaint::on_pushButton_Right_clicked()
{paint_xe += step_val;update_para();this->update();}void CImgPaint::on_pushButton_reset_clicked()
{reset_para();update_para();this->update();
}
这样,可以通过点击按钮来完成图片的移动、缩放。
6.鼠标拖动、滚轮实现图片拖动及缩放
重写如下虚函数
public slots:void wheelEvent(QWheelEvent *event);bool event(QEvent *event);void mouseDoubleClickEvent(QMouseEvent *event);
void CImgPaint::mouseDoubleClickEvent(QMouseEvent *event)
{if(event->button()==Qt::LeftButton && paint_rect.contains(event->pos())){reset_para();update_para();this->update();}
}
bool CImgPaint::event(QEvent *event)
{qDebug()<<"event";if(event->type() == QEvent::MouseButtonPress ){QMouseEvent *mouse = dynamic_cast<QMouseEvent* >(event);//QPoint temp = mouse->pos();if(mouse->button()==Qt::LeftButton && paint_rect.contains(mouse->pos())){mouse_press_flag = true;QApplication::setOverrideCursor(Qt::OpenHandCursor);mouse_pos_pre = mouse->pos();}qDebug()<<"MouseButtonPress";}else if(event->type() == QEvent::MouseButtonRelease){QMouseEvent *mouse = dynamic_cast<QMouseEvent* >(event);//判断鼠标是否是左键释放,且之前是在绘画区域if(mouse->button()==Qt::LeftButton && mouse_press_flag ){QApplication::setOverrideCursor(Qt::ArrowCursor); //改回鼠标样式mouse_press_flag=false;}qDebug()<<"MouseButtonRelease";}if(event->type() == QEvent::MouseMove) //移动图片{if(mouse_press_flag){QMouseEvent *mouse = dynamic_cast<QMouseEvent* >(event);mouse_pos_cur = mouse->pos();int dx = mouse_pos_cur.x() - mouse_pos_pre.x();int dy = mouse_pos_cur.y() - mouse_pos_pre.y();mouse_pos_pre = mouse_pos_cur;paint_xe += dx;paint_ye += dy;update_para();this->update();}qDebug()<<"MouseMove";}return QWidget::event(event);
}void CImgPaint::wheelEvent(QWheelEvent *event)
{if (event->delta()>0) //上滑,缩小{on_pushButton_zoomIn_clicked();}else //下滑,放大{on_pushButton_zoomOut_clicked();}event->accept();
}
可实现鼠标拖动、滚轮的方式来完成图片的拖动、缩放。
源码下载地址(附使用方法):
https://download.csdn.net/download/xiaohuolong1827/78238541
原链接
相关文章:
Qt 完成图片的缩放拖动
1. 事件和函数 主要使用事件paintEvent(QPaintEvent *event)和drawTiledPixmap函数实现绘图。 paintEvent事件在改变窗口大小、移动窗口、手动调用update等情形下会被调用。需先了解下绘图该函数的用法。 - QPainter::drawTiledPixmap(int x, int y, int w, int h, const QPi…...
Linux 内核工具 iptables 配置TCP/UDP端口转发(命令参考)
1、配置TCP端口转发 把本机20000/TCP端口转发到7.7.7.7:20000 iptables -t nat -A PREROUTING -p tcp --dport 20000 -j DNAT --to-destination 7.7.7.7:20000 iptables -t nat -A POSTROUTING -j MASQUERADE 2、配置UDP端口转发 把本机20000/UDP端口转发到7.7.7.7:20000 i…...
love 2d Lua 俄罗斯方块超详细教程
源码已经更新在CSDN的码库里: git clone https://gitcode.com/funsion/love2d-game.git 一直在找Lua 能快速便捷实现图形界面的软件,找了一堆,终于发现love2d是小而美的原生lua图形界面实现的方式。 并参考相关教程做了一个更详细的&#x…...
SpringBoot+ElasticSearch实现文档内容抽取、高亮分词、全文检索
需求 产品希望我们这边能够实现用户上传PDF、WORD、TXT之内得文本内容,然后用户可以根据附件名称或文件内容模糊查询文件信息,并可以在线查看文件内容。 一、环境 项目开发环境: 后台管理系统springbootmybatis_plusmysqles 搜索引擎&#…...
利用Redis实现简单的短信登录
在现代应用中,短信登录是一种常见的用户认证方式。它提供了一种便捷的登录方式,同时也增加了账户的安全性。在本文中,我们将介绍如何使用 Redis 实现短信登录的功能,并提供相应的 Java 实现层代码。 1、短信验证码的生成与存储当用…...
在 Linux 中通过 SSH 执行远程命令时,无法自动加载环境变量(已解决)
问题场景 目前我的环境变量都存储在 /etc/profile 文件中,当我通过远程 SSH 执行一些命令时,提示命令找不到,如下所示: 问题出现原因 这里找到了一张出自尚硅谷的图片,很好的解释了该问题: 这是由于 Linu…...
c++使用类的一些注意事项
前言: 本篇内容为前面的补充,介绍了我们使用类时需要注意些什么以及一些编译器的优化,可能有些理解不到位或者错误,请斧正。 目录 前言: 1.再谈构造函数 2.(c98)隐式类型转换中的编译器的优…...
C++蓝桥考级一级到十八级的考点内容整理
以下是C蓝桥考级一级到十八级的考点内容整理: C一级考点内容 C程序基本结构 初步了解C编程了解C程序基本结构:头文件、命名空间、主函数、基本输入输出 cin、cout C二级考点内容 数据类型与变量 掌握编程中数学表达式的计算方式基础数据类型、变量的…...
C++智能指针简单剖析
导读 最近在补看《C Primer Plus》第六版,这的确是本好书,其中关于智能指针的章节解析的非常清晰,一解我以前的多处困惑。C面试过程中,很多面试官都喜欢问智能指针相关的问题,比如你知道哪些智能指针?shar…...
mysql笔记:25. docker环境中mysql主从复制、主主复制实操
文章目录 一、准备工作1. 安装配置Docker2. 准备MySQL相关的配置和数据目录 二、基于日志点的主从复制1. 配置Master服务器1.1 修改配置文件1.2. 在docker中启动Master节点1.3. 创建用户并授权 2. 配置Slave1服务器2.1. 修改配置2.2. 启动服务2.3. 指定Master2.4. 开始复制 3. …...
大数据面试专题 -- kafka
1、什么是消息队列? 是一个用于存放数据的组件,用于系统之间或者是模块之间的消息传递。 2、消息队列的应用场景? 主要是用于模块之间的解耦合、异步处理、日志处理、流量削峰 3、什么是kafka? kafka是一种基于订阅发布模式的…...
深度学习入门简单实现一个神经网络
实现一个三层神经网络 引言测试数据 代码 引言 今天我们实现一个简单的神经网络 俩个输入神经元 隐藏层两个神经元 一个输出神经元 激活函数我们使用sigmoid 优化方法使用梯度下降 我们前期准备是需要把这些神经元的关系理清楚 x1:第一个输入 x2:第二个…...
win11 环境配置 之 Jmeter(JDK17版本)
一、安装 JDK 1. 安装 jdk 截至当前最新时间: 2024.3.27 jdk最新的版本 是 官网下载地址: https://www.oracle.com/java/technologies/downloads/ 建议下载 jdk17 另存为到该电脑的 D 盘下,新建jdk文件夹 开始安装到 jdk 文件夹下 2. 配…...
Windows下载使用nc(netcat)命令
‘nc’ 不是内部或外部命令,也不是可运行的程序? 点击链接地址,下载压缩包。 完成后解压 使用方式(三种): 1、直接双击exe使用 2、把这个exe放到cmd启动的默认路径下 放到默认路径下,使用nc&a…...
istio 设置 istio-proxy sidecar 的 resource 的 limit 和 request
方式一 修改 configmap 查看当前 sidecar 的 cpu 和 memory 的配额 在 istio-sidecar-injector 中查找,修改后重启 pod 可以生效(下面那个 proxy_init 配置不管,不知道是干嘛的) 方式二 如果是通过 iop 安装的 istio…...
flutter弹框
alertDialog:弹框 simpleDialog:选择弹框 showModalBottomSheet:底部弹出弹框 showtoast:三方插件弹框 Navigator.of(context).pop(点击取消) 关闭弹框,传递参数 import package:flutter/material.dart; // import package:flutter/cupertino.dart; import package:flut…...
2013年认证杯SPSSPRO杯数学建模B题(第一阶段)流行音乐发展简史全过程文档及程序
2013年认证杯SPSSPRO杯数学建模 B题 流行音乐发展简史 原题再现: 随着互联网的发展,流行音乐的主要传播媒介从传统的电台和唱片逐渐过渡到网络下载和网络电台等。网络电台需要根据收听者的已知喜好,自动推荐并播放其它音乐。由于每个人喜好…...
代码随想录算法训练营第39天 | 62.不同路径, 63不同路径II
Leetcode - 62:不同路径 题目: 一个机器人位于一个 m x n 网格的左上角 (起始点在下图中标记为 “Start” )。 机器人每次只能向下或者向右移动一步。机器人试图达到网格的右下角(在下图中标记为 “Finish” &#…...
Redis 的慢日志
Redis 的慢日志 Redis 的慢日志(Slow Log)是用于记录执行时间超过预设阈值的命令请求的系统。慢日志可以帮助运维人员和开发人员识别潜在的性能瓶颈,定位那些可能导致 Redis 性能下降或响应延迟的慢查询。以下是 Redis 慢日志的相关细节&…...
第十四届蓝桥杯第十题:蜗牛分享
问题描述 输入格式 输出格式 输出共一行,一个浮点数表示答案(四舍五入保留两位小数)。 样例输入 3 1 10 11 1 1 2 1样例输出 4.20样例说明 蜗牛路线:(0,0)→(1,0)→(1,1)→(10,1)→(10,0)→(11,0)(0,0)→(1,0)→(1,1)→(10,1…...
不懂技术的老板,如何避免过度依赖核心技术人员
在这个日新月异、技术驱动的时代,即使作为非技术背景的老板,也深知核心技术人员的价值。然而,过度依赖某几位核心技术人员,不仅可能带来经营风险,还可能限制企业的创新与发展。那么,不懂技术的老板…...
Vue系列-el挂载
<!DOCTYPE html> <html lang"en"> <head><meta charset"UTF-8"><meta name"viewport" content"widthdevice-width, initial-scale1.0"><title>el:挂载点</title> </head> <body&g…...
python--os和os.path模块
>>> import os >>> #curdir #获取当前脚本的绝对路径 >>> os.curdir . >>> import os.path >>> #获取绝对路径 >>> os.path.abspath(os.curdir) C:\\Users\\GUOGUO>>> #chdir #修改当前目录 >&g…...
前端通用命名规范和Vue项目命名规范
通用命名规范 变量和常量命名:变量和常量的命名应具有描述性,清晰明了,使用驼峰命名法或下划线命名法,例如:firstName、MAX_VALUE。 函数和方法命名:函数和方法的命名应该能够准确描述其功能&…...
NTP服务搭建
一、ntpd和ntpdate区别 1.ntpd是自动执行的远程更新本地系统时钟的服务,是平滑同步; 2.ntpdate是手工执行的服务,也就是一般用它执行一次本地时间更新,如果做成半自动,可以写入到crontab自动任务,从而变成…...
Linux离线安装mysql,node,forever
PS:本文是基于centos7实现的,要求系统能够查看ifconfig和unzip解压命令, 实现无网络可安装运行 首先现在百度网盘的离线文件包****安装Xftp 和 Xshell 把机房压缩包传到 home目录下****解压unzip 包名.zip 获取IP先获取到 linux 主机的ip ifconfig Xftp 连接输入IP,然后按照…...
WPF中获取TreeView以及ListView获取其本身滚动条进行滚动
实现自行调节scoll滚动的位置(可相应获取任何控件中的内部滚动条) TreeView:TreeViewAutomationPeer lvap new TreeViewAutomationPeer(treeView); var svap lvap.GetPattern(PatternInterface.Scroll) as ScrollViewerAutomationPeer; var scroll svap.Owner as ScrollVie…...
C语言: 指针讲解
为什么需要指针? (1)指针的使用使得不同区域的代码可以轻易的共享内存数据。当然你也可以通过数据的复制达到相同的效果,但是这样往往效率不太好,因为诸如结构体等大型数据,占用的字节数多,复制很消耗性能…...
C#使用Stopwatch类来实现计时功能
前言 在 C# 中,Stopwatch 类是用于测量经过的时间的工具类,提供了高精度的计时功能。Stopwatch 类位于 System.Diagnostics 命名空间中。通常情况下,使用 Stopwatch 的流程是创建一个 Stopwatch 对象,然后调用 Start 方法开始计时…...
ubuntu18.04安装qt
ubuntu18.04安装qt 1、下载文件 比如我下载的是5.13.0版本 下载链接 2、安装 wget https://download.qt.io/archive/qt/5.13/5.13.0/qt-opensource-linux-x64-5.13.0.runsudo chmod x qt-opensource-linux-x64-5.13.0.runsudo ./qt-opensource-linux-x64-5.13.0.run参考文…...
增加网站访问量/成都谷歌seo
在第一次安装的时候出现这个错误信息 解决办法: 修改config.inc.php文件里的两个属性值为: $tlCfg->log_path TL_ABS_PATH . logs . DIRECTORY_SEPARATOR ;$g_repositoryPath TL_ABS_PATH . "upload_area" . DIRECTORY_SEPARATOR; 配置中文 在config…...
wordpress 5.2.2/百度官方网址
文章目录1、什么是弱网测试2、弱网环境的影响3、弱网环境测试场景4、使用Fiddler进行弱网测试(1)Fiddler模拟弱网环境(2)设置弱网的参数(3)进行弱网测试对比(4)恢复设置5、补充&…...
sublime怎么做网站/微信朋友圈推广平台
如何来测试龙门铣床的准确度? 现代社会,机床的使用已经是非常常见了,尤其是近几年推陈出新的出来来好几款高精度的机床。但也正式因为如此,人们对于他的保养问题就有所怠慢了,惹得龙门铣床工作是频频出现问题。下面给大家说说这…...
wordpress防止机器人注册/吉林seo技术交流
一、元素事件的绑定 为按钮绑定鼠标进入,鼠标离开,点击事件 第一种方法 $("#btn").mouseenter(function () {$(this).css("backgroundColor","red");});$("#btn").mouseleave(function () {$(this).css("backgroundColor"…...
手机网站建设比较好的公司/百度指数批量
面试官的问题层出不穷,我们在面试的时候总会被问到一些没接触的东西,所以就需要一个比较全面的面试复习,今天我就分享一个Java全能面试通关手册,希望能在面试方面帮助到大家。 大厂面试题目录阿里一面1.说⼀下ArrayList和LinkedL…...
wordpress发信设置/许昌网站推广公司
1.安装依赖 pip install --upgradetools pip install numpy Matplotlib 2.安装opencv-python(网络一定要通畅) pip install opencv-python...