• QT学习笔记(四)——在QLabel显示的影像上画图形,并和影像同步放大缩小


    实现在QLabel显示的影像上画图形,并和影像同步放大缩小

    关于影像在QLabel的显示,如何随鼠标滚轮实现放大缩小,可以参考我的上一篇博客
    QT学习笔记(三)——vs2019+Qt实现打开影像并以鼠标为中心用滚轮控制图片缩放
    本篇博客接着这个继续实现如何在QLabel打开的图像上画一个形状(以矩形为例),并且能让这个图形和影像一起随鼠标滚轮放大缩小。

    1.首先新建一个myLabel类,重写myLabel的paintEvent方法。

    这个方法的目的是保证你能在这个myLabel类生成的对象中画图并显示

    //myLabel.h
    #include 
    #include 
    #include 
    #include 
    #include 
    #include 
    class myLabel :
        public QLabel
    {
        Q_OBJECT
    public:
        myLabel(QWidget* parent = nullptr);
        //~myLabel();
        //重写绘制事件
        virtual void paintEvent(QPaintEvent* event) override;
        void DrawRangle(int x, int y, int w, int h);
       
        int x;
        int y;
        int w;
        int h;
    };
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    //myLabel.cpp
    #include "myLabel.h"
    
    myLabel::myLabel(QWidget *parent):QLabel(parent) {}
    
    void myLabel::DrawRangle(int xx, int yy, int hh, int ww)
    {
        x = xx;
        y = yy;
        w = ww;
        h = hh;
    
        update();
    }
    //重写绘制事件
    void myLabel::paintEvent(QPaintEvent* event)
    {
        QLabel::paintEvent(event);//必须有,才能让背景图片显示出来
        QPainter painter(this);
        QPen pen;
        pen.setColor(Qt::blue);
        pen.setWidth(5);
        painter.setPen(pen);
        painter.drawRect(QRect(x, y, w, h));
        painter.end();
    }
    
    • 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

    2.然后在tstQt中将myLabel.h头文件包含进去,并加入新的成员变量(矩形框)

    并在tstQt类中将之前定义的imgLabel的变量类型从QLabel改为自己定义的myLabel,即在tstQt.h中

     myLabel* imgLabel;//图像显示框
    //加入新的成员变量
    QPoint onept;//矩形左上角点在影像中的坐标
    int w;//矩形宽度
    int h;
    
    • 1
    • 2
    • 3
    • 4
    • 5

    同时,在tstQt.cpp中的InitImage()函数中,将imgLabel的初始化修改为:

    imgLabel = new myLabel(dock_Image);
    
    • 1

    并在该函数末尾添加:

        w = 50;
        h = 50;
        onept.setX(50);
        onept.setY(50);
        imgLabel->DrawRangle(onept.x(), onept.y(), w,h);
    
    • 1
    • 2
    • 3
    • 4
    • 5

    这时候运行,就可以看到多了一个蓝色的矩形框了,但是这个矩形相对于label的左上角点的固定的,当鼠标放缩影像时,矩形框不会跟随放缩。因此需要修改wheelevent()函数,下面直接放上该函数的完整代码:

    void tstQt::wheelEvent(QWheelEvent* event)
    {
        int dockWin_pos = scrollArea->geometry().y()+dock_Image->geometry().y();
        int pp = scrollArea->pos().y();
        QPoint pt = onept;//要画的矩形左上角点
    
        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中的坐标,这里的79是窗体标题的高度
    
        imgLabel->setPixmap(QPixmap::fromImage(m_image));      // 这一句是为了防止自适应窗口之后进行放缩图像分辨率变低,所以label重新加载原始影像
        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 stepr = (double)(step) / (double)(currentWidth);  //   (1.0+stepr)为放缩比例=r
    
        currentWidth += step;                                  // 对当前图像的高累加
        currentHeight += (int)(step*ratio+0.5);                    // 对当前图像的宽累加(四舍五入)
    
        double r = (double)currentWidth / (double)m_image.width();//始终计算相对于原影像的放缩比例,用来计算所画点放缩后的坐标
    
        int x = onept.x() * r+0.5;
        int y = onept.y() * r + 0.5;
        int wtmp = w * r ;
        int htmp = h * r ;
    
        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 = stepr * th + 0.5;
        int move_y = stepr * tv + 0.5;
    
        tmph->setValue(tmph->value()+ move_x);
        tmpv->setValue(tmpv->value() + move_y);
    
        //对于矩形进行刷新
        //imgLabel->DrawRangle(100, 100, 20, 10);
        imgLabel->DrawRangle(x,y,wtmp,htmp);
    }
    
    • 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
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63

    其实主要就是添加了计算每次刷新时矩形左上角点的坐标,以及新的长宽,每次update()时,会清除上一次画的,所以放缩前的矩形刷新后就不会存在了。运行效果:
    打开影像:
    在这里插入图片描述
    放大:
    在这里插入图片描述
    缩小:

    在这里插入图片描述
    放大缩小时,该矩形在图片上的位置是不变的。

    3.还有自适应窗口的函数autosize()也要做相应修改

    void tstQt::autoSize() // 自适应窗口
    {
        imgLabel->setPixmap(QPixmap::fromImage(m_image));
        imgLabel->resize(m_image.width(), m_image.height());
        QImage Img;
        double ImgRatio = 1.0 * imgLabel->pixmap()->toImage().width() / imgLabel->pixmap()->toImage().height();     // 图像宽高比
        double WinRatio = 1.0 * (scrollArea->width() - 2) / (scrollArea->height() - 2); // 窗口宽高比
        if (ImgRatio > WinRatio)        // 图像宽高比大于图像宽高比
        {
            Img = imgLabel->pixmap()->toImage().scaled((scrollArea->width() - 2), (scrollArea->width() - 2) / ImgRatio, Qt::IgnoreAspectRatio, Qt::SmoothTransformation);
        }
        else                            // 图像宽高比小于等于图像宽高比
        {
            Img = imgLabel->pixmap()->toImage().scaled((scrollArea->height() - 2) * ImgRatio, (scrollArea->height() - 2), Qt::IgnoreAspectRatio, Qt::SmoothTransformation);
        }
        imgLabel->setPixmap(QPixmap::fromImage(Img));   // 显示图像
        imgLabel->resize(Img.width(), Img.height());
    
        double r = (double)Img.width() / (double)m_image.width();
    
        int x = onept.x() * r + 0.5;
        int y = onept.y() * r + 0.5;
        int wtmp = w * r;
        int htmp = h * r;
    
        imgLabel->DrawRangle(x, y, wtmp, htmp);
    }
    
    • 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
  • 相关阅读:
    C++总结(8):STL容器适配器之stack、queue、priority_queue详解
    基础学习1_目标检测的评估标准
    Nginx配置文件及Nginx服务优化
    远程仓库创建好后,出现版本冲突,提交不成功,pull也会失败的解决方法
    浪潮信息InManage升级发布 三大功能释放数据中心运维管理压力
    使用Ant Design Vue的Table组件,解决点击任意内容详情,点击返回分页器页数默认回到第一页的问题
    系统学习区块链、Solidity 和前后端全栈 Web3 开发
    35【Storage接口】
    STM32连接WIFI-ESP8266实战—AP模式运用
    Python报错:KeyError: ‘820‘
  • 原文地址:https://blog.csdn.net/weixin_44153180/article/details/128048110