#ifndef DRAW_SCENE_H
#define DRAW_SCENE_H
#include<QGraphicsScene>
#include<QGraphicsEllipseItem>
#include<qDebug>
#include<QGraphicsRectItem>
#include<QGraphicsSceneMouseEvent>
#include<QPainter>
#include<QVector2D>
#include<QVector3D>
#include <QtMath>
#include<QStyleOptionGraphicsItem>
#include<QPointF>
#define PI 3.14159265358979
class draw_rect_item :public QObject,public QGraphicsItem
{
Q_OBJECT
public:
draw_rect_item(QGraphicsItem *parent = Q_NULLPTR);
~draw_rect_item();
public:
enum MOUSEHANDLE
{
handleNone =0,
handleTopLeft =1,
handleTopMiddle=2,
handleTopRight =3,
handleBottomLeft =4,
handleBottomMiddle=5,
handleBottomRight =6,
handleMiddleLeft =7,
handleMiddleRight =8,
} ;
enum ItemOperator
{
t_none=0,
t_move=1,
t_resize=2,
t_rotate=3,
t_painter=4,
} ;
QRectF itemRect ; //item的轮廓
private:
ItemOperator m_itemOper = t_none;
MOUSEHANDLE m_bhandleSelected=MOUSEHANDLE::handleNone ; //resize操作,时按压状态
std::map<MOUSEHANDLE,QRectF>m_handles; //item中resize操作中的九个矩形
QRectF outLineRect; //item的外轮廓
static QImage m_rotateIcon;
QPixmap m_rotatepixmap;
private:
QPointF m_pos; // 本地所坐标点击的点
QPointF m_pressedPos; // 场景坐标点击的点
QPointF m_startPos; // Item在场景坐标的起始坐标
QTransform m_transform;
qreal m_rotate=0.0; //旋转角度
QPointF m_rotateCenter=QPointF(0,0);
QPointF m_rectCenterOffset;
private:
bool m_isResizeable =true;
bool m_isRatioScale =true;
qreal m_rationValue=1.0;
QSize m_size;
const float m_frotateTolerance=0;
qreal m_nInterval=0;
qreal m_nEllipseWidth =10;
private:
draw_rect_item::MOUSEHANDLE handleAt(const QPointF& point); //得到鼠标位置处的状态
void initIcon();
void updateHandlesPos(); //调整四周小矩形的位置和大小。
QCursor getRotateCursor(const qreal angle) ; //旋转光标
protected:
void paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget = Q_NULLPTR);
void mousePressEvent(QGraphicsSceneMouseEvent *event);
void mouseMoveEvent(QGraphicsSceneMouseEvent *event);
void mouseReleaseEvent(QGraphicsSceneMouseEvent *event);
QRectF boundingRect() const override; //响应item事件的边界的一个函数
private:
virtual void mouseMoveRotateOperator(const QPointF rotateStartPos, const QPointF rotateEndPos, const QPointF rotateCenterPos);
virtual void mouseMoveResizeOperator(draw_rect_item::MOUSEHANDLE dir, const QPointF& loacalPos);
virtual void mouseMoveMoveOperator(const QPointF& localpos);
};
#include<QGraphicsSceneMouseEvent>
#include<QMouseEvent>
class draw_scene:public QGraphicsScene
{
public:
enum ItemOperator
{
t_none,
t_move,
t_resize,
t_rotate,
t_painter
};
private:
ItemOperator m_itemOper = t_none;
QPointF m_startPos; // Item在场景坐标的起始坐标
QPointF m_endPos; // Item在场景坐标的结束坐标
QRectF* rectF =NULL;
public:
explicit draw_scene();
private:
//QGraphicsSimpleTextItem* rect_text_Item;
//QGraphicsLineItem rect_line_Item;
QGraphicsRectItem* rect_item;
protected:
void mousePressEvent(QGraphicsSceneMouseEvent *event);
void mouseReleaseEvent(QGraphicsSceneMouseEvent *event);
void mouseMoveEvent(QGraphicsSceneMouseEvent *event);
void keyPressEvent(QKeyEvent * event)
{
qDebug() << "Custom scene keyPressEvent.";
QGraphicsScene::keyPressEvent(event);
}
private:
virtual void mouseMovepaintOperator(const QPointF& scenePos ,const QPointF& localpos);
};
#endif // DRAW_SCENE_H
#include "draw_scene.h"
QImage draw_rect_item::m_rotateIcon;
draw_rect_item::draw_rect_item(QGraphicsItem *parent)
: QGraphicsItem(parent)
{
setAcceptHoverEvents(true);
//这里不可以把标志设为可移动
//this->setFlags( QGraphicsItem::ItemIsFocusable| QGraphicsItem::ItemIsSelectable | QGraphicsItem::ItemSendsGeometryChanges);
this->setFlag(QGraphicsItem::ItemIsSelectable, true);
initIcon();
}
void draw_rect_item::initIcon()
{
//初始化变量
m_size = QSize(500,100);
m_handles.insert(std::make_pair(MOUSEHANDLE::handleTopLeft,QRectF()));
m_handles.insert(std::make_pair(MOUSEHANDLE::handleTopMiddle,QRectF()));
m_handles.insert(std::make_pair(MOUSEHANDLE::handleTopRight,QRectF()));
m_handles.insert(std::make_pair(MOUSEHANDLE::handleBottomLeft,QRectF()));
m_handles.insert(std::make_pair(MOUSEHANDLE::handleBottomMiddle,QRectF()));
m_handles.insert(std::make_pair(MOUSEHANDLE::handleBottomRight,QRectF()));
m_handles.insert(std::make_pair(MOUSEHANDLE::handleMiddleLeft,QRectF()));
m_handles.insert(std::make_pair(MOUSEHANDLE::handleMiddleRight,QRectF()));
QPointF centerPos(m_rotateCenter);//item项的中心,为原点
itemRect = QRectF(centerPos.x()-m_size.width()/2,centerPos.y()-m_size.height()/2,m_size.width(),m_size.height()); //本地坐标系下,矩形左上角的位置。根据本地坐标系,判断鼠标点击的位置
outLineRect =itemRect.adjusted(-m_nInterval,-m_nInterval,m_nInterval,m_nInterval);//画圆之前,把outline矩形的中心=圆的外切矩形中心重合
}
draw_rect_item::~draw_rect_item()
{
}
//得到鼠标处,鼠标的状态标志
draw_rect_item::MOUSEHANDLE draw_rect_item::handleAt(const QPointF &point)
{
for (auto it : m_handles)
{
if (it.second.contains(point))
{
qDebug()<< "it.first"<<it.first;
return it.first;
}
}
qDebug()<< "it.first MOUSEHANDLE::handleNone";
return MOUSEHANDLE::handleNone;
}
void draw_rect_item::mouseMoveResizeOperator(draw_rect_item::MOUSEHANDLE dir, const QPointF &localPos)
{
//itemRect; //返回当前的矩形 outLineRect;//返回当前矩形的外边框矩形
switch (dir)
{
case MOUSEHANDLE::handleTopLeft:
itemRect.setTopLeft(localPos.toPoint()); //本地坐标系上,item的坐标
break;
case MOUSEHANDLE::handleTopMiddle:
itemRect.setTop(localPos.y());
qDebug()<<m_rotate;
this->setCursor(getRotateCursor(m_rotate));
break;
case MOUSEHANDLE::handleTopRight:
itemRect.setTopRight(localPos);
break;
case MOUSEHANDLE::handleBottomLeft:
itemRect.setBottomLeft(localPos);
break;
case MOUSEHANDLE::handleBottomMiddle:
itemRect.setBottom(localPos.y());
break;
case MOUSEHANDLE::handleBottomRight:
itemRect.setBottomRight(localPos);
break;
case MOUSEHANDLE::handleMiddleLeft:
itemRect.setLeft(localPos.x());
break;
case MOUSEHANDLE::handleMiddleRight:
itemRect.setRight(localPos.x());
break;
default:
this->setCursor(Qt::ArrowCursor);
break;
}
qDebug()<<"itemRect_center"<<itemRect.center();
}
//重载-。qpointf可以和qreal类型相加
QPointF operator-(const QPointF& pointF ,qreal value)
{
return QPointF(pointF.x() - value, pointF.y() - value);
}
void draw_rect_item::updateHandlesPos()
{
outLineRect =itemRect.adjusted(-m_nInterval,-m_nInterval,m_nInterval,m_nInterval);//画圆之前,把outline矩形的中心=圆的外切矩形中心重合
QSize EllipseWidth=QSize(m_nEllipseWidth,m_nEllipseWidth);
m_handles[MOUSEHANDLE::handleTopLeft] = QRectF(outLineRect.topLeft()- (m_nEllipseWidth/2),EllipseWidth);
m_handles[MOUSEHANDLE::handleTopMiddle] = QRectF(QPoint(outLineRect.center().x(),outLineRect.top()- (m_nEllipseWidth/2)),EllipseWidth);
m_handles[MOUSEHANDLE::handleTopRight] = QRectF(outLineRect.topRight()- m_nEllipseWidth/2,EllipseWidth);
m_handles[MOUSEHANDLE::handleBottomLeft] = QRectF(outLineRect.bottomLeft()- m_nEllipseWidth/2,EllipseWidth);
m_handles[MOUSEHANDLE::handleBottomMiddle] = QRectF(QPoint(outLineRect.center().x(),outLineRect.bottom()- (m_nEllipseWidth/2)),EllipseWidth);
m_handles[MOUSEHANDLE::handleBottomRight] = QRectF(outLineRect.bottomRight()- m_nEllipseWidth/2,EllipseWidth);
m_handles[MOUSEHANDLE::handleMiddleLeft] = QRectF(QPoint(outLineRect.left()- (m_nEllipseWidth/2),outLineRect.center().y()),EllipseWidth);
m_handles[MOUSEHANDLE::handleMiddleRight] = QRectF(QPoint(outLineRect.right()- (m_nEllipseWidth/2),outLineRect.center().y()),EllipseWidth);
}
//重载+。qpointf可以和qreal类型相加
QPointF operator+(const QPointF& point, qreal value)
{
return QPointF(point.x() + value, point.y() + value);
}
//重载+。qreal可以和qpointf类型相加
QPointF operator+(qreal value, const QPointF& point)
{
return QPointF(point.x() + value, point.y() + value);
}
QCursor draw_rect_item::getRotateCursor(const qreal angle)
{
if(m_rotateIcon.isNull())
{
m_rotateIcon.load("C:/Users/dell/Pictures/Camera Roll/22.jpg");
}
m_rotatepixmap=QPixmap::fromImage(m_rotateIcon);
QPainter* painter;
painter->drawPixmap(QRect(outLineRect.topRight().x() - m_nEllipseWidth / 2, outLineRect.topRight().y() - m_nEllipseWidth / 2, m_nEllipseWidth, m_nEllipseWidth), m_rotatepixmap);
QTransform transform;
transform.rotate(angle);
QPixmap rotatedPixmap = m_rotatepixmap.transformed(transform);
return QCursor(rotatedPixmap);
}
//绘制item时,主要时通过item本地坐标系。实现改变m_size的大小,距离本地坐标系的原点,进行缩放,旋转,
void draw_rect_item::paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget)
{
QPen pen= painter->pen();
pen.setStyle(Qt::DashLine);
painter->setPen(pen);
painter->drawRect(itemRect);
if (!this->isSelected())
return;
painter->drawRect(outLineRect);
painter->setPen(Qt::NoPen);
painter->setBrush(Qt::red);
updateHandlesPos(); //矩形上九点圆形的外接矩形
for (auto it : m_handles)
{
painter->drawEllipse(it.second);
}
painter->setBrush(Qt::blue);
painter->drawEllipse(boundingRect());
painter->setBrush(Qt::black);
painter->drawEllipse(QRectF(pos(),QSize(10,10)));
painter->setBrush(Qt::green);
painter->drawEllipse(QRectF( transformOriginPoint(),QSize(10,10)));
}
void draw_rect_item::mousePressEvent(QGraphicsSceneMouseEvent *event)
{
QPointF scenepos= event->scenePos(); //获取场景坐标
QPointF pos=event->pos();
m_pos=pos; //旋转的起始点
m_pressedPos=scenepos;
m_startPos=this->pos();
m_bhandleSelected= handleAt(pos); //返回mousehandle的状态
if(m_bhandleSelected==MOUSEHANDLE::handleNone)
{
m_itemOper=t_rotate;
// m_itemOper = t_move;
}
else
{
m_itemOper= t_resize;
}
return QGraphicsItem::mousePressEvent(event); // 调用基类的处理
}
void draw_rect_item::mouseMoveEvent(QGraphicsSceneMouseEvent *event)
{
QPointF sceneMovePos=event->scenePos(); //场景坐标
QPointF localPos=event->pos(); //图像项坐标(一般位图形项的中心位原点)
QPointF pt1,pt2,delta;
pt1 = transformOriginPoint();
pt2 = boundingRect().center();
delta = pt1 - pt2;
setTransform(transform().translate(delta.x(),delta.y()));
setTransformOriginPoint(boundingRect().center());
moveBy(-delta.x(),-delta.y());
if(m_itemOper == t_move )
{
mouseMoveMoveOperator(sceneMovePos);//移动ok
}
if(m_itemOper ==t_resize)
{
//当我们设置了新的中心点,如果已经有了旋转角度的话,那么则会出现平移的现象
mouseMoveResizeOperator(m_bhandleSelected,localPos); //放大缩小操作ok
}
else if(m_itemOper == t_rotate)
{
// QPointF delta = pos() - boundingRect().center() ; // 将本地坐标原点移动到中心,
qDebug()<<"start================";
qDebug()<<"pos-boundingRect.center="<<delta;
qDebug()<<"op"<<pos();
qDebug()<<boundingRect().center();
m_rotateCenter=boundingRect().center();
//当再次旋转时,item进行重绘,重绘坐标原点仍然是原来的pos()坐标。重绘时先绘制图形,然后应用该图形的transform。而rect.center()的坐标已经不再是缩放时的center,所以会发生图形漂移
mouseMoveRotateOperator(m_pressedPos, sceneMovePos,m_rotateCenter); //旋转图形,仍以局部坐标为准。
}
this->update();
QGraphicsItem::mouseMoveEvent(event);
}
void draw_rect_item::mouseReleaseEvent(QGraphicsSceneMouseEvent *event)
{
qDebug()<<"QGraphicsrectItem_release";
QGraphicsItem::mouseReleaseEvent(event);
}
QRectF draw_rect_item::boundingRect() const
{
QRectF boundingToleranceRect= outLineRect.adjusted(-m_frotateTolerance,-m_frotateTolerance,m_frotateTolerance,m_frotateTolerance);//旋转矩形的容忍度
// if(!this->isSelected())
// return rectF;
return boundingToleranceRect;
}
//旋转中心=scene中的坐标系(点)。
//旋转起点=scene中的坐标系(点)。
//旋转终点=scene中的坐标系(点)。 用scene中的坐标系,解决拖影
//刚开始0度时。旋转中心不会变,如果矩形
void draw_rect_item::mouseMoveRotateOperator(const QPointF rotateStartPos, const QPointF rotateEndPos, const QPointF rotateCenterPos)
{
QVector2D startVec(rotateStartPos.x() - rotateCenterPos.x() ,rotateStartPos.y()- rotateCenterPos.y()); //(0,0)为本地坐标系的原点
startVec.normalize();
QVector2D endVec(rotateEndPos.x()- rotateCenterPos.x() ,rotateEndPos.y()- rotateCenterPos.y());
endVec.normalize();//获取单位向量(向量/模长)
qreal dotValue = QVector2D::dotProduct(startVec,endVec); //单位向量点乘,等于cos0
if (dotValue > 1.0)
dotValue = 1.0;
else if (dotValue < -1.0)
dotValue = -1.0;
dotValue=qAcos(dotValue);
if(isnan(dotValue))
{
dotValue=0.0;
}
qreal angle =dotValue*1.0/(PI/180); //获取角度
QVector3D crossValue =QVector3D::crossProduct(QVector3D(startVec,1.0),QVector3D(endVec,1.0));//向量叉乘获取角度
qDebug()<<crossValue.z()<<"crossValue.z()";
if(crossValue.z()<0)
{
angle=-angle;
}
m_rotate+=angle;
setPos(rotateCenterPos);
setTransformOriginPoint(rotateCenterPos);
setRotation(m_rotate);
m_pressedPos=rotateEndPos;
}
void draw_rect_item::mouseMoveMoveOperator(const QPointF &scenePos)
{
qreal xInterVal =scenePos.x() - m_pressedPos.x();
qreal yInterVal =scenePos.y() - m_pressedPos.y();
this->setPos(m_startPos +QPointF(xInterVal,yInterVal));//设置在场景中位置
this->update();
}
draw_scene::draw_scene()
{
}
void draw_scene::mousePressEvent(QGraphicsSceneMouseEvent *event)
{
QGraphicsScene::mousePressEvent(event);
qDebug()<<"scene_press";
}
void draw_scene::mouseReleaseEvent(QGraphicsSceneMouseEvent *event)
{
QGraphicsScene::mouseReleaseEvent(event);
}
void draw_scene::mouseMoveEvent(QGraphicsSceneMouseEvent *event)
{
QGraphicsScene::mouseMoveEvent(event);
}
void draw_scene::mouseMovepaintOperator(const QPointF &scenePos, const QPointF &localpos)
{
qDebug()<<rectF;
QLineF line(m_startPos,scenePos);
rectF->setBottomRight(scenePos);
rectF=&rectF->normalized();
}
问题一:图形项,在修改之后还是会漂移。表现为拉伸之后,旋转。图像项漂移。