• vs2019+Qt实现打开影像并用鼠标滚轮控制图片缩放


    vs2019+Qt实现打开影像并以鼠标为中心用滚轮控制图片缩放

    之前写了一个博客讲怎么显示一张影像,那个是基于Qpainter的
    今天使用QLabel来显示影像,并且用鼠标滚轮控制缩放。
    关于图像的打开和显示,主要参考这个博客
    关于如何使图片自适应窗口与铺满窗口,可以参考这个博客
    这两个博客出自同一作者,都很详细。
    其中按照第二个博客运行后存在的问题是,点了铺满窗口后,再点自适应窗口,图片没有反应。
    解决方法:
    1.在头文件添加成员变量

        QImage m_image;
    
    • 1

    2.在InitImage()函数和File_open()两个中将img拷贝到m_image中,即在这两个函数中都添加:

        m_image = img->copy();
    
    • 1

    3.在fullSize()和autoSize()两个函数中最前面添加

    imgLabel->setPixmap(QPixmap::fromImage(m_image));
    imgLabel->resize(m_image.width(), m_image.height());
    
    • 1
    • 2

    这样每次点击这俩按钮的时候,label的大小都会回到原影像的大小。

    接着这个博客,下面主要讲一下如何用鼠标滚轮控制图片缩放。

    1.此时打开较大的影像,鼠标滚轮是控制图片上下移动的。因此首先重写 QAbstractScrollArea 类的wheelEvent函数,让它什么都不要做

    void QAbstractScrollArea::wheelEvent(QWheelEvent* event)
    {
        return;
    }
    
    • 1
    • 2
    • 3
    • 4

    2.然后实现滚轮控制label放大缩小

    void tstQt::wheelEvent(QWheelEvent* event)
    {
        double ratio = (double)m_image.height() / (double)m_image.width();//图像的比例
        QPoint numDegrees;                                     // 定义指针类型参数numDegrees用于获取滚轮转角
        numDegrees = event->angleDelta();                      // 获取滚轮转角
        int step = 0;                                          // 设置中间参数step用于将获取的数值转换成整数型
        if (!numDegrees.isNull())                              // 判断滚轮是否转动
        {
            step = numDegrees.y();                             // 将滚轮转动数值传给中间参数step
        }
        event->accept();                                       // 获取事件
        int currentWidth = imgLabel->width();                  // 获取当前图像的宽
        int currentHeight = imgLabel->height();               // 获取当前图像的高
        currentWidth += step;                                  // 对当前图像的高累加
        currentHeight += (int)(step*ratio);                                 // 对当前图像的宽累加
        if (step > 0)                                          // 判断图像是放大还是缩小
        {
            QString imgsize = QString("图像放大,尺寸为:%1 * %2")
                .arg(currentWidth).arg(currentHeight);
            qDebug() << imgsize;                               // 打印放大后的图像尺寸
        }
        else
        {
            QString imgsize = QString("图像缩小,尺寸为:%1 * %2")
                .arg(currentWidth).arg(currentHeight);
            qDebug() << imgsize;                                // 打印缩小后的图像尺寸
        }
        imgLabel->resize(currentWidth, currentHeight);          // 通过更新图像显示控件的大小来更新图像大小
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29

    这里设置了一个图像比例因子ratio,可以使图像缩放过程中,比例不要失调。
    但是如果先点击了铺满窗口在进行缩放,那label的大小就会变成窗口大小,图像比例就会失调。

    但是这时候会发现缩放是以label的左上角为原点进行缩放的,但常用的是以鼠标为中心进行缩放,所以下面实现此部分

    1.首先在wheelEvent函数最前面添加代码

    	int dockWin_pos = scrollArea->geometry().y()+dock_Image->geometry().y();
        QScrollBar* tmph = scrollArea->horizontalScrollBar();
        QScrollBar* tmpv = scrollArea->verticalScrollBar();
        QPoint pos = event->pos();//得到当前鼠标在窗口的位置
        QRect tmplab = imgLabel->geometry();//获得imglabel的位置
        int th = pos.x() - tmplab.x();   // 缩放前鼠标点在label中的坐标
        int tv = pos.y() - tmplab.y() - dockWin_pos;
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7

    这里需要注意的是鼠标位置pos的坐标,它的坐标原点并不是显示图像的区域的左上角,而是。。。不说了,看图
    在这里插入图片描述
    所以我自己量了一下图中两个坐标原点的y轴相差大约79,在上面代码中用dockWin_pos来表示。因为这个坐标原点一开始我没整明白,导致我浪费了一天时间找bug…
    2.计算label的放缩比例,因为前面代码是直接加减了一个step,现在计算一下放缩比例就是step/currentwidth
    这一句要加在currentWidth变化前。

     double r = (double)(step) / (double)(currentWidth);  //   放缩比例
    
    • 1

    3.计算滚轮变化量

        int move_x = r * th;
        int move_y = r * tv;
        
        tmph->setValue(tmph->value()+ move_x);
        tmpv->setValue(tmpv->value() + move_y)
    
    • 1
    • 2
    • 3
    • 4
    • 5

    关于整个的原理,得自己画图理解一下了

    最后放一下完整的weelEvent()函数代码:

    void tstQt::wheelEvent(QWheelEvent* event)
    {
    	int dockWin_pos = scrollArea->geometry().y()+dock_Image->geometry().y();
    	
        QScrollBar* tmph = scrollArea->horizontalScrollBar();
        QScrollBar* tmpv = scrollArea->verticalScrollBar();
        QPoint pos = event->pos();//得到当前鼠标在窗口的位置
        QRect tmplab = imgLabel->geometry();//获得imglabel的位置
    
        int th = pos.x() - tmplab.x();
        int tv = pos.y() - tmplab.y() - dockWin_pos;//缩放前鼠标点在label中的坐标,这里的dockWin_pos是窗体标题的高度
    
        imgLabel->setPixmap(QPixmap::fromImage(m_image));      // 显示图像
        double ratio = (double)m_image.height() / (double)m_image.width();//图像的比例
        QPoint numDegrees;                                     // 定义指针类型参数numDegrees用于获取滚轮转角
        numDegrees = event->angleDelta();                      // 获取滚轮转角
        int step = 0;                                          // 设置中间参数step用于将获取的数值转换成整数型
        if (!numDegrees.isNull())                              // 判断滚轮是否转动
        {
            step = numDegrees.y();                             // 将滚轮转动数值传给中间参数step
        }
        event->accept();                                       // 获取事件
        int currentWidth = imgLabel->width();                  // 获取当前图像的宽
        int currentHeight = imgLabel->height();                // 获取当前图像的高
    
        double r = (double)(step) / (double)(currentWidth);  //   放缩比例
    
        currentWidth += step;                                  // 对当前图像的高累加
        currentHeight += (int)(step*ratio);                    // 对当前图像的宽累加
        if (step > 0)                                          // 判断图像是放大还是缩小
        {
            QString imgsize = QString("图像放大,尺寸为:%1 * %2")
                .arg(currentWidth).arg(currentHeight);
            qDebug() << imgsize;                               // 打印放大后的图像尺寸
        }
        else
        {
            QString imgsize = QString("图像缩小,尺寸为:%1 * %2")
                .arg(currentWidth).arg(currentHeight);
            qDebug() << imgsize;                                // 打印缩小后的图像尺寸
        }
        imgLabel->resize(currentWidth, currentHeight);          // 通过更新图像显示控件的大小来更新图像大小
    
        int move_x = r * th;
        int move_y = r * tv;
    
        tmph->setValue(tmph->value()+ move_x);
        tmpv->setValue(tmpv->value() + move_y);
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
  • 相关阅读:
    【软件测试】超细HttpRunner接口自动化框架使用案例,一篇策底打通...
    14:00面试,14:06就出来了,问的问题有点变态。。。
    增强AWS ECS监控:批量生产监控设置
    MySQL-(2)
    Linux 利用inotify和rsync服务实现数据实时同步
    骗赞小程序(仅供恶搞)
    Docker之最全使用基础命令(帮助启动类命令、镜像类命令、容器类命令)
    【论文阅读】-- DeepVisualInsight: 深度分类训练时空因果关系的时间旅行可视化
    你认为低代码能够完全取代程序猿吗?
    MySQL的备份和恢复
  • 原文地址:https://blog.csdn.net/weixin_44153180/article/details/127954235