Qt 完成图片的缩放拖动

1. 事件和函数

主要使用事件paintEvent(QPaintEvent *event)和drawTiledPixmap函数实现绘图。

  1. paintEvent事件在改变窗口大小、移动窗口、手动调用update等情形下会被调用。
  2. 需先了解下绘图该函数的用法。 - QPainter::drawTiledPixmap(int x, int y, int w, int h, const QPixmap &pm, int sx, int sy)
  3. 效果:

2. 建立项目

假设已新建了mainwindow项目。现再添加一界面用于单独显示图片,作为子窗口供调用(当然,也可在main.c直接调用,作为父窗口)。

1)右击界面文件---添加新文件---QT---QT设计师界面类---choose---Dialog without buttons。类名为CImgPaint。

打开ui文件,添加控件,主要是label和button,

具体属性列表如下:

其中,label控件仅仅是提供绘图的区域,但最终绘图不是绘在label控件上。

3. 头文件添加变量,编写构造函数

头文件中包含头文件

cpp 复制代码
#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;
#endif

namespace 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;//记录鼠标位置

构造函数中,添加输入图片的读取,以及变量初始化。

cpp 复制代码
#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_OPENCV
    cv::Mat img = cv::imread("lenaGray.jpg",-1);
    pix_src = get_pixmap_from_mat(img);
#else
    QImage qimg ;
    qimg.load("./lenaGray.jpg");
    pix_src = pix_src.fromImage(qimg);
#endif
    paint_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函数的各参数。

cpp 复制代码
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 首先确定实际绘图的起点,绘图的起点应在画布的大小范围内 //
    // 若期望的起点超出画布上限,则设置截取图像的起始位置sy
    paint_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 首先确定实际绘图的起点,绘图的起点应在画布的大小范围内 //
    // 若期望的起点超出画布上限,则设置截取图像的起始位置sx
    paint_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文件中重写该事件函数

cpp 复制代码
public slots:
    void paintEvent(QPaintEvent *event);
cpp 复制代码
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函数的各参数。

cpp 复制代码
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.鼠标拖动、滚轮实现图片拖动及缩放

重写如下虚函数

cpp 复制代码
public slots:
    void wheelEvent(QWheelEvent *event);
    bool event(QEvent *event);
    void mouseDoubleClickEvent(QMouseEvent *event);
cpp 复制代码
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

原链接

相关推荐
落落落sss10 分钟前
MybatisPlus
android·java·开发语言·spring·tomcat·rabbitmq·mybatis
简单.is.good28 分钟前
【测试】接口测试与接口自动化
开发语言·python
Yvemil71 小时前
MQ 架构设计原理与消息中间件详解(二)
开发语言·后端·ruby
程序员是干活的1 小时前
私家车开车回家过节会发生什么事情
java·开发语言·软件构建·1024程序员节
我是陈泽1 小时前
一行 Python 代码能实现什么丧心病狂的功能?圣诞树源代码
开发语言·python·程序员·编程·python教程·python学习·python教学
优雅的小武先生1 小时前
QT中的按钮控件和comboBox控件和spinBox控件无法点击的bug
开发语言·qt·bug
Death2001 小时前
使用Qt进行TCP和UDP网络编程
网络·c++·qt·tcp/ip
虽千万人 吾往矣1 小时前
golang gorm
开发语言·数据库·后端·tcp/ip·golang
创作小达人1 小时前
家政服务|基于springBoot的家政服务平台设计与实现(附项目源码+论文+数据库)
开发语言·python
郭二哈1 小时前
C++——list
开发语言·c++·list