jjzjj

QT学习笔记(三)——vs2019+Qt实现打开影像并以鼠标为中心用滚轮控制图片缩放

冷面杰拉德 2024-03-16 原文

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

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

    QImage m_image;

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

    m_image = img->copy();

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

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

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

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

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

void QAbstractScrollArea::wheelEvent(QWheelEvent* event)
{
    return;
}

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);          // 通过更新图像显示控件的大小来更新图像大小
}

这里设置了一个图像比例因子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;

这里需要注意的是鼠标位置pos的坐标,它的坐标原点并不是显示图像的区域的左上角,而是。。。不说了,看图

所以我自己量了一下图中两个坐标原点的y轴相差大约79,在上面代码中用dockWin_pos来表示。因为这个坐标原点一开始我没整明白,导致我浪费了一天时间找bug…
2.计算label的放缩比例,因为前面代码是直接加减了一个step,现在计算一下放缩比例就是step/currentwidth
这一句要加在currentWidth变化前。

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

3.计算滚轮变化量

    int move_x = r * th;
    int move_y = r * tv;
    
    tmph->setValue(tmph->value()+ move_x);
    tmpv->setValue(tmpv->value() + move_y)

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

最后放一下完整的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);
}

有关QT学习笔记(三)——vs2019+Qt实现打开影像并以鼠标为中心用滚轮控制图片缩放的更多相关文章

  1. ruby-on-rails - Railstutorial : db:populate vs. 工厂女孩 - 2

    在railstutorial中,作者为什么选择使用这个(代码list10.25):http://ruby.railstutorial.org/chapters/updating-showing-and-deleting-usersnamespace:dbdodesc"Filldatabasewithsampledata"task:populate=>:environmentdoRake::Task['db:reset'].invokeUser.create!(:name=>"ExampleUser",:email=>"example@railstutorial.org",:passwo

  2. Qt Designer的简单使用 - 2

    在前面两节的例子中,主界面窗口的尺寸和标签控件显示的矩形区域等,都是用C++代码编写的。窗口和控件的尺寸都是预估的,控件如果多起来,那就不好估计每个控件合适的位置和大小了。用C++代码编写图形界面的问题就是不直观,因此Qt项目开发了专门的可视化图形界面编辑器——QtDesigner(Qt设计师)。通过QtDesigner就可以很方便地创建图形界面文件*.ui,然后将ui文件应用到源代码里面,做到“所见即所得”,大大方便了图形界面的设计。本节就演示一下QtDesigner的简单使用,学习拖拽控件和设置控件属性,并将ui文件应用到Qt程序代码里。使用QtDesigner设计界面在开始菜单中找到「Q

  3. LC滤波器设计学习笔记(一)滤波电路入门 - 2

    目录前言滤波电路科普主要分类实际情况单位的概念常用评价参数函数型滤波器简单分析滤波电路构成低通滤波器RC低通滤波器RL低通滤波器高通滤波器RC高通滤波器RL高通滤波器部分摘自《LC滤波器设计与制作》,侵权删。前言最近需要学习放大电路和滤波电路,但是由于只在之前做音乐频谱分析仪的时候简单了解过一点点运放,所以也是相当从零开始学习了。滤波电路科普主要分类滤波器:主要是从不同频率的成分中提取出特定频率的信号。有源滤波器:由RC元件与运算放大器组成的滤波器。可滤除某一次或多次谐波,最普通易于采用的无源滤波器结构是将电感与电容串联,可对主要次谐波(3、5、7)构成低阻抗旁路。无源滤波器:无源滤波器,又称

  4. CAN协议的学习与理解 - 2

    最近在学习CAN,记录一下,也供大家参考交流。推荐几个我觉得很好的CAN学习,本文也是在看了他们的好文之后做的笔记首先是瑞萨的CAN入门,真的通透;秀!靠这篇我竟然2天理解了CAN协议!实战STM32F4CAN!原文链接:https://blog.csdn.net/XiaoXiaoPengBo/article/details/116206252CAN详解(小白教程)原文链接:https://blog.csdn.net/xwwwj/article/details/105372234一篇易懂的CAN通讯协议指南1一篇易懂的CAN通讯协议指南1-知乎(zhihu.com)视频推荐CAN总线个人知识总

  5. 深度学习部署:Windows安装pycocotools报错解决方法 - 2

    深度学习部署:Windows安装pycocotools报错解决方法1.pycocotools库的简介2.pycocotools安装的坑3.解决办法更多Ai资讯:公主号AiCharm本系列是作者在跑一些深度学习实例时,遇到的各种各样的问题及解决办法,希望能够帮助到大家。ERROR:Commanderroredoutwithexitstatus1:'D:\Anaconda3\python.exe'-u-c'importsys,setuptools,tokenize;sys.argv[0]='"'"'C:\\Users\\46653\\AppData\\Local\\Temp\\pip-instal

  6. ruby - 我正在学习编程并选择了 Ruby。我应该升级到 Ruby 1.9 吗? - 2

    我完全不是程序员,正在学习使用Ruby和Rails框架进行编程。我目前正在使用Ruby1.8.7和Rails3.0.3,但我想知道我是否应该升级到Ruby1.9,因为我真的没有任何升级的“遗留”成本。缺点是什么?我是否会遇到与普通gem的兼容性问题,或者甚至其他我不太了解甚至无法预料的问题? 最佳答案 你应该升级。不要坚持从1.8.7开始。如果您发现不支持1.9.2的gem,请避免使用它们(因为它们很可能不被维护)。如果您对gem是否兼容1.9.2有任何疑问,您可以在以下位置查看:http://www.railsplugins.or

  7. arrays - Ruby 数组 += vs 推送 - 2

    我有一个数组数组,想将元素附加到子数组。+=做我想做的,但我想了解为什么push不做。我期望的行为(并与+=一起工作):b=Array.new(3,[])b[0]+=["apple"]b[1]+=["orange"]b[2]+=["frog"]b=>[["苹果"],["橙子"],["Frog"]]通过推送,我将推送的元素附加到每个子数组(为什么?):a=Array.new(3,[])a[0].push("apple")a[1].push("orange")a[2].push("frog")a=>[[“苹果”、“橙子”、“Frog”]、[“苹果”、“橙子”、“Frog”]、[“苹果”、“

  8. Ruby#index 方法 VS 二进制搜索 - 2

    给定一个元素和一个数组,Ruby#index方法返回元素在数组中的位置。我使用二进制搜索实现了我自己的索引方法,期望我的方法会优于内置方法。令我惊讶的是,内置的在实验中的运行速度大约是我的三倍。有Rubyist知道原因吗? 最佳答案 内置#indexisnotabinarysearch,这只是一个简单的迭代搜索。但是,它是用C而不是Ruby实现的,因此自然可以快几个数量级。 关于Ruby#index方法VS二进制搜索,我们在StackOverflow上找到一个类似的问题:

  9. ruby - 我如何学习 ruby​​ 的正则表达式? - 2

    如何学习ruby​​的正则表达式?(对于假人) 最佳答案 http://www.rubular.com/在Ruby中使用正则表达式时是一个很棒的工具,因为它可以立即将结果可视化。 关于ruby-我如何学习ruby​​的正则表达式?,我们在StackOverflow上找到一个类似的问题: https://stackoverflow.com/questions/1881231/

  10. ruby-on-rails - lovdbyless VS 社区引擎……哪个最好? - 2

    随着ruby​​被引入为新的编程救世主,我想知道是否有人基于易用性、运行所需的资源、可用性和易定制性而有偏好。两者有更好的吗? 最佳答案 好吧,任何基于Rails的社交网络应用程序的比较都应该包括insoshi(http://portal.insoshi.com/)。话虽这么说,这三个都非常相似,区别在于实现细节。Lovd和Insoshi都是完整的Rails应用程序;它旨在供您将它们用作入门工具包,并使用您自己的自定义功能对其进行扩展。另一方面,CommunityEngine是一个Rails插件。这意味着您可以更轻松地向现有Rail

随机推荐