这篇文章是基于我之前写的文章《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