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…...
接口测试中缓存处理策略
在接口测试中,缓存处理策略是一个关键环节,直接影响测试结果的准确性和可靠性。合理的缓存处理策略能够确保测试环境的一致性,避免因缓存数据导致的测试偏差。以下是接口测试中常见的缓存处理策略及其详细说明: 一、缓存处理的核…...
04-初识css
一、css样式引入 1.1.内部样式 <div style"width: 100px;"></div>1.2.外部样式 1.2.1.外部样式1 <style>.aa {width: 100px;} </style> <div class"aa"></div>1.2.2.外部样式2 <!-- rel内表面引入的是style样…...
MySQL账号权限管理指南:安全创建账户与精细授权技巧
在MySQL数据库管理中,合理创建用户账号并分配精确权限是保障数据安全的核心环节。直接使用root账号进行所有操作不仅危险且难以审计操作行为。今天我们来全面解析MySQL账号创建与权限分配的专业方法。 一、为何需要创建独立账号? 最小权限原则…...
听写流程自动化实践,轻量级教育辅助
随着智能教育工具的发展,越来越多的传统学习方式正在被数字化、自动化所优化。听写作为语文、英语等学科中重要的基础训练形式,也迎来了更高效的解决方案。 这是一款轻量但功能强大的听写辅助工具。它是基于本地词库与可选在线语音引擎构建,…...
Java毕业设计:WML信息查询与后端信息发布系统开发
JAVAWML信息查询与后端信息发布系统实现 一、系统概述 本系统基于Java和WML(无线标记语言)技术开发,实现了移动设备上的信息查询与后端信息发布功能。系统采用B/S架构,服务器端使用Java Servlet处理请求,数据库采用MySQL存储信息࿰…...
【Nginx】使用 Nginx+Lua 实现基于 IP 的访问频率限制
使用 NginxLua 实现基于 IP 的访问频率限制 在高并发场景下,限制某个 IP 的访问频率是非常重要的,可以有效防止恶意攻击或错误配置导致的服务宕机。以下是一个详细的实现方案,使用 Nginx 和 Lua 脚本结合 Redis 来实现基于 IP 的访问频率限制…...
CSS | transition 和 transform的用处和区别
省流总结: transform用于变换/变形,transition是动画控制器 transform 用来对元素进行变形,常见的操作如下,它是立即生效的样式变形属性。 旋转 rotate(角度deg)、平移 translateX(像素px)、缩放 scale(倍数)、倾斜 skewX(角度…...
uniapp 开发ios, xcode 提交app store connect 和 testflight内测
uniapp 中配置 配置manifest 文档:manifest.json 应用配置 | uni-app官网 hbuilderx中本地打包 下载IOS最新SDK 开发环境 | uni小程序SDK hbulderx 版本号:4.66 对应的sdk版本 4.66 两者必须一致 本地打包的资源导入到SDK 导入资源 | uni小程序SDK …...
实战设计模式之模板方法模式
概述 模板方法模式定义了一个操作中的算法骨架,并将某些步骤延迟到子类中实现。模板方法使得子类可以在不改变算法结构的前提下,重新定义算法中的某些步骤。简单来说,就是在一个方法中定义了要执行的步骤顺序或算法框架,但允许子类…...
倒装芯片凸点成型工艺
UBM(Under Bump Metallization)与Bump(焊球)形成工艺流程。我们可以将整张流程图分为三大阶段来理解: 🔧 一、UBM(Under Bump Metallization)工艺流程(黄色区域ÿ…...
