QT实现图片缩放的同时随意框选区域并保存截图

本文介绍在QT中自定义myGraphicRectItem类,实现图片上的矩形框绘制、拉伸、缩放和拖动功能。通过鼠标事件判断用户操作,支持不同状态下的光标变化,提供保存框选截图的功能。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

这篇文章是基于我之前写的文章《QT下实现图片的自适应显示、缩放(以鼠标位置为中心进行缩放)、拖动、以及重置》https://blog.youkuaiyun.com/weixin_43935474/article/details/89327314#comments
之前的文章里说过自己重写了QGraphicsItem类(自己的类命名为ImageWidget),从而实现的图片的缩放,拖动,及重置显示。
这篇文章里主要新写了一个myGraphicRectItem类,还是继承自QGraphicsItem类,用来实现:
1.在图像显示区域绘制矩形框
2.鼠标点击矩形的任意一条边可进行矩形的拉伸,同时鼠标样式更改
3.鼠标点击矩形右下角并拖动可进行矩形的缩放
4.鼠标按住矩形内区域并移动可拖动矩形
在这里插入图片描述
myGraphicRectItem.h代码如下:

#ifndef MYGRAPHICRECTITEM_H
#define MYGRAPHICRECTITEM_H
#include <QObject>
#include <QWidget>
#include <QMouseEvent>
#include <QGraphicsScene>
#include <QGraphicsRectItem>
#include <QGraphicsSceneMouseEvent>
#include <QRect>
#include <QPainter>
enum STATE_FLAG{
    DEFAULT_FLAG=0,
    MOV_LEFT_LINE,//标记当前为用户按下矩形的左边界区域
    MOV_TOP_LINE,//标记当前为用户按下矩形的上边界区域
    MOV_RIGHT_LINE,//标记当前为用户按下矩形的右边界区域
    MOV_BOTTOM_LINE,//标记当前为用户按下矩形的下边界区域
    MOV_RIGHTBOTTOM_RECT,//标记当前为用户按下矩形的右下角
    MOV_RECT//标记当前为鼠标拖动图片移动状态
};
class myGraphicRectItem:public QObject,public QGraphicsItem
{
    Q_OBJECT
public:
    myGraphicRectItem(QGraphicsItem *parent = nullptr);
    //myGraphicRectItem(QRectF m_OriginRect = QRectF(0,0,100,100));
    QRectF  boundingRect() const;
    ~myGraphicRectItem();
    void setRectSize(QRectF mrect);
    void paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget);
    void mousePressEvent(QGraphicsSceneMouseEvent *event);
    void mouseMoveEvent(QGraphicsSceneMouseEvent *event);
    void mouseReleaseEvent(QGraphicsSceneMouseEvent *event);
    QRectF getCrtPosRectToSceen();
private:
    QRectF  m_oldRect;
    bool    m_bResize;
    QRectF  m_insicedRectf;
    QRectF  m_leftRectf;
    QRectF  m_topRectf;
    QRectF  m_rightRectf;
    QRectF  m_bottomRectf;
    QRectF  m_rbRectf;
    QPointF m_startPos;
    STATE_FLAG m_StateFlag;
protected:
};
#endif // MYGRAPHICRECTITEM_H

myGraphicRectItem.cpp

#include "mygraphicrectitem.h"

myGraphicRectItem::myGraphicRectItem(QGraphicsItem *parent):
    m_bResize(false),
    m_oldRect(QRectF(0,0,100,100)),
    m_StateFlag(DEFAULT_FLAG)
{
    m_insicedRectf = QRectF(m_oldRect.x()+4,m_oldRect.y()+4,m_oldRect.width()-8,m_oldRect.height()-8);
    m_leftRectf = QRectF(m_oldRect.x(),m_oldRect.y(),4,m_oldRect.height()-4);
    m_topRectf = QRectF(m_oldRect.x()+4,m_oldRect.y(),m_oldRect.width()-4,4);
    m_rightRectf = QRectF(m_oldRect.right()-4,m_oldRect.y()+4,4,m_oldRect.height()-8);
    m_bottomRectf = QRectF(m_oldRect.x(),m_oldRect.bottom()-4,m_oldRect.width()-4,4);
    m_rbRectf = QRectF(m_oldRect.right()-4,m_oldRect.bottom()-4,4,4);
    setToolTip("Click and drag me!");  //提示
    setCursor(Qt::ArrowCursor);   //改变光标形状,手的形状
    setFlag(QGraphicsItem::ItemIsMovable);
    //    setAcceptDrops(true);
}

QRectF myGraphicRectItem::boundingRect() const
{
    return QRectF(m_oldRect);
}

myGraphicRectItem::~myGraphicRectItem()
{

}

void myGraphicRectItem::setRectSize(QRectF mrect)
{
        m_oldRect = mrect;
        m_insicedRectf = QRectF(m_oldRect.x()+4,m_oldRect.y()+4,m_oldRect.width()-8,m_oldRect.height()-8);
        m_leftRectf = QRectF(m_oldRect.x(),m_oldRect.y(),4,m_oldRect.height()-4);
        m_topRectf = QRectF(m_oldRect.x()+4,m_oldRect.y(),m_oldRect.width()-4,4);
        m_rightRectf = QRectF(m_oldRect.right()-4,m_oldRect.y()+4,4,m_oldRect.height()-8);
        m_bottomRectf = QRectF(m_oldRect.x(),m_oldRect.bottom()-4,m_oldRect.width()-4,4);
        m_rbRectf = QRectF(m_oldRect.right()-4,m_oldRect.bottom()-4,4,4);
}

void myGraphicRectItem::paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget)
{
    QPen mPen = QPen(Qt::yellow);
    painter->setPen(mPen);
    painter->drawRect(m_oldRect);
}

void myGraphicRectItem::mousePressEvent(QGraphicsSceneMouseEvent *event)
{
    if(event->button()== Qt::LeftButton)
    {
        m_startPos = event->pos();//鼠标左击时,获取当前鼠标在图片中的坐标,
        if(m_insicedRectf.contains(m_startPos))//在矩形内框区域时按下鼠标,则可拖动图片
        {
            setCursor(Qt::ArrowCursor);   //改变光标形状,手的形状
            m_StateFlag = MOV_RECT;//标记当前为鼠标拖动图片移动状态
        }
        else if(m_leftRectf.contains(m_startPos))
        {
            setCursor(Qt::SizeHorCursor);
            m_StateFlag = MOV_LEFT_LINE;//标记当前为用户按下矩形的左边界区域
        }
        else if(m_rightRectf.contains(m_startPos))
        {
            setCursor(Qt::SizeHorCursor);
            m_StateFlag = MOV_RIGHT_LINE;//标记当前为用户按下矩形的右边界区域
        }
        else if(m_topRectf.contains(m_startPos))
        {
            setCursor(Qt::SizeVerCursor);
            m_StateFlag = MOV_TOP_LINE;//标记当前为用户按下矩形的上边界区域
        }
        else if(m_bottomRectf.contains(m_startPos))
        {
            setCursor(Qt::SizeVerCursor);
            m_StateFlag = MOV_BOTTOM_LINE;//标记当前为用户按下矩形的下边界区域
        }
        else if(m_rbRectf.contains(m_startPos))
        {
            setCursor(Qt::SizeFDiagCursor);
            m_StateFlag = MOV_RIGHTBOTTOM_RECT;//标记当前为用户按下矩形的右下角
        }
    }
    else
    {
        QGraphicsItem::mousePressEvent(event);
    }
}

void myGraphicRectItem::mouseMoveEvent(QGraphicsSceneMouseEvent *event)
{
    if(m_StateFlag == MOV_RECT)
    {
        QPointF point = (event->pos() - m_startPos);
        moveBy(point.x(), point.y());
    }
    else if(m_StateFlag == MOV_LEFT_LINE)
    {
        if(event->pos().x()>(m_oldRect.right()-10))
        {
            return;
        }
        else
        {
            QRectF newRect(m_oldRect);
            newRect.setLeft(event->pos().x());
            setRectSize(newRect);
            scene()->update();//必须要用scene()->update(),不能用update();否则会出现重影
        }
    }
    else if(m_StateFlag == MOV_TOP_LINE)
    {
        if(event->pos().y()>(m_oldRect.bottom()-10))
        {
            return;
        }
        else
        {
            QRectF newRect(m_oldRect);
            newRect.setTop(event->pos().y());
            setRectSize(newRect);
            scene()->update();//必须要用scene()->update(),不能用update();否则会出现重影
        }
    }
    else if(m_StateFlag == MOV_RIGHT_LINE)
    {
        if(event->pos().x()<(m_oldRect.left()+10))
        {
            return;
        }
        else
        {
            QRectF newRect(m_oldRect);
            newRect.setRight(event->pos().x());
            setRectSize(newRect);
            scene()->update();//必须要用scene()->update(),不能用update();否则会出现重影
        }
    }
    else if(m_StateFlag == MOV_BOTTOM_LINE)
    {
        if(event->pos().y()<(m_oldRect.top()+10))
        {
            return;
        }
        else
        {
            QRectF newRect(m_oldRect);
            newRect.setBottom(event->pos().y());
            setRectSize(newRect);
            scene()->update();//必须要用scene()->update(),不能用update();否则会出现重影
        }
    }
    else if(m_StateFlag == MOV_RIGHTBOTTOM_RECT)
    {
        if(event->pos().y()<(m_oldRect.top()+10))
        {
            return;
        }
        else if(event->pos().x()<(m_oldRect.left()+10))
        {
            return;
        }
        else
        {
            QRectF newRect(m_oldRect);
            newRect.setBottomRight(event->pos());
            setRectSize(newRect);
            scene()->update();//必须要用scene()->update(),不能用update();否则会出现重影
        }
    }
    else {
        QGraphicsItem::mouseMoveEvent(event);
    }
}

void myGraphicRectItem::mouseReleaseEvent(QGraphicsSceneMouseEvent *event)
{
    setCursor(Qt::ArrowCursor);
    if(m_StateFlag == MOV_RECT)
    {
        m_StateFlag = DEFAULT_FLAG;
    }
    else {
        QGraphicsItem::mouseReleaseEvent(event);
    }
}

QRectF myGraphicRectItem::getCrtPosRectToSceen()
{
    QRectF retRect = QRectF(m_oldRect.x()+pos().x(),m_oldRect.y()+pos().y(),m_oldRect.width(),m_oldRect.height());
    return retRect;
}

上面类的使用方式如下,其中m_qgraphicsScene为QGraphicsScene场景,请结合上篇文章内容理解:

void MainWindow::on_pushButton__DrawRect_clicked()
{
    myGraphicRectItem *m_myGraphicRectItem;
    m_myGraphicRectItem = new myGraphicRectItem();//实例化myGraphicRectItem
    m_myGraphicRectItem->setRectSize(QRectF(-100,-100,200,200));//设置矩形大小,以m_qgraphicsScene的中心为原点,边长200的正方形
    m_qgraphicsScene->addItem(m_myGraphicRectItem);//将绘制的矩形添加到m_qgraphicsScene场景中
    m_qgraphicsScene->setFocusItem(m_myGraphicRectItem);
}

接下来是截取矩形区域的图片,并保存。实现过程如下:
1.用户点击“保存框选截图”按钮后,主程序调用ImageWidget类的getImgFromRect(QRectF rectf)函数,实现获取矩形区域对应的图像的信息
2.在getImgFromRect()函数内,因为用户在之前的操作中,可能对图片进行了缩放和拖动操作,所以我们需要将矩形rectf进行坐标转换,转换后为temprectf,然后在原图中拷贝temprectf区域,并以QPixmap 变量的形式返回。
3.在主程序中将函数返回的QPixmap 保存到程序执行目录下。getImgFromRect()函数如下:

QPixmap ImageWidget::getImgFromRect(QRectF rectf)//rectf是外界传进来的以QGraphicsScene为坐标基准的矩形区域(即界面上看到的图片显示区域的正中央为(0,0)点)
{
    qreal nwidthOffset = pos().x();//pos()为当前m_pic图片正中央相对于显示控件的正中央(0,0)点偏移的位置
    qreal nheightOffset = pos().y();
    QRectF temprectf = QRectF(rectf.x()/m_scaleValue+m_pix.width()/2-nwidthOffset/m_scaleValue,rectf.y()/m_scaleValue+m_pix.height()/2-nheightOffset/m_scaleValue,rectf.width()/m_scaleValue,rectf.height()/m_scaleValue);
    //temprectf是将rectf转换为当前m_pic图片中的对应位置区域
    QPixmap retPixmap = m_pix.copy(temprectf.toRect());//拷贝m_pic图片中的对应区域
    return retPixmap;
}

源码:https://download.youkuaiyun.com/download/weixin_43935474/11545517

评论 42
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

GreenHandBruce

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值