实现图元的旋转操作,通过鼠标移动到boundingRect四角的handle附近触发

This commit is contained in:
duanshengchao 2024-08-26 17:27:37 +08:00
parent d9faf99ab5
commit f59af2bf9d
17 changed files with 266 additions and 41 deletions

View File

@ -44,6 +44,7 @@ set(H_HEADER_FILES
include/util/baseSelector.h
include/util/creatingSelector.h
include/util/movingSelector.h
include/util/rotationSelector.h
include/util/scalingSelector.h
include/util/editingSelector.h
include/util/selectorManager.h
@ -65,6 +66,7 @@ set(CPP_SOURCE_FILES
source/util/baseSelector.cpp
source/util/creatingSelector.cpp
source/util/movingSelector.cpp
source/util/rotationSelector.cpp
source/util/scalingSelector.cpp
source/util/editingSelector.cpp
source/util/selectorManager.cpp

View File

@ -19,7 +19,7 @@ public:
m_pen = QPen(Qt::NoPen);
m_brush = QBrush(QColor(rand() % 32 * 8, rand() % 32 * 8, rand() % 32 * 8));
m_dWidth = m_dHeight = 0;
m_pMovingCopy = nullptr;
m_pOperationCopy = nullptr;
}
virtual ~AbstractShapeType()
@ -71,10 +71,11 @@ public:
return HandleTag::H_none;
}
//移动副本相关
virtual void createMovingCopy() {}
virtual void removeMovingCopy() {}
virtual void moveMovingCopy(const QPointF&) {}
//操作副本相关
virtual void createOperationCopy() {}
virtual void removeOperationCopy() {}
virtual void moveOperationCopy(const QPointF&) {}
virtual void rotateOperationCopy(const double&) {}
virtual void resize(int,double, double, const QPointF&) {}
virtual void move(const QPointF&) {}
@ -84,6 +85,19 @@ public:
//handle相关
virtual int handleCount() { return m_vecHanle.count(); }
virtual ItemControlHandle* getHandle(int nHandle)
{
ItemControlHandle* handle = nullptr;
for(auto it = m_vecHanle.begin(); it != m_vecHanle.end(); it++)
{
if((*it)->getTag() == nHandle)
{
handle = (*it);
return handle;
}
}
return handle;
}
virtual void setHandleVisible(bool bVisible)
{
for(auto it = m_vecHanle.begin(); it != m_vecHanle.end(); it++)
@ -161,13 +175,68 @@ public:
case H_left:
(*it)->move(boundRect.x() - nMargin, boundRect.y() + boundRect.height() * 0.5);
break;
case H_rotate_leftTop:
{
ItemControlHandle* handle = getHandle(H_leftTop);
if(handle)
{
int nSize = handle->getSize();
QPointF pt = handle->pos();
(*it)->move(pt.x() - nSize - 1, pt.y() - nSize - 1);
}
else
(*it)->setVisible(false);
break;
}
case H_rotate_rightTop:
{
ItemControlHandle* handle = getHandle(H_rightTop);
if(handle)
{
int nSize = handle->getSize();
QPointF pt = handle->pos();
(*it)->move(pt.x() + nSize + 1, pt.y() - nSize - 1);
}
else
(*it)->setVisible(false);
break;
}
case H_rotate_rightBottom:
{
ItemControlHandle* handle = getHandle(H_rightBottom);
if(handle)
{
int nSize = handle->getSize();
QPointF pt = handle->pos();
(*it)->move(pt.x() + nSize + 1, pt.y() + nSize + 1);
}
else
(*it)->setVisible(false);
break;
}
case H_rotate_leftBottom:
{
ItemControlHandle* handle = getHandle(H_leftBottom);
if(handle)
{
int nSize = handle->getSize();
QPointF pt = handle->pos();
(*it)->move(pt.x() - nSize - 1, pt.y() + nSize + 1);
}
else
(*it)->setVisible(false);
break;
}
default:
break;
}
}
}
protected:
virtual QRectF boundingRect() const { return m_boundingRect; }
virtual QPainterPath shape()
{
@ -182,7 +251,7 @@ protected:
double m_dHeight;
QRectF m_boundingRect;
QGraphicsPathItem* m_pMovingCopy; //图元移动时的副本
QGraphicsPathItem* m_pOperationCopy; //图元移动和旋转时的操作副本
QPointF m_movingIniPos; //移动副本开始移动初始点
QVector<ItemControlHandle*> m_vecHanle;
@ -196,9 +265,10 @@ public:
GraphicsBaseItem(QGraphicsItem *parent);
virtual ~GraphicsBaseItem();
virtual void createMovingCopy();
virtual void removeMovingCopy();
virtual void moveMovingCopy(const QPointF&);
virtual void createOperationCopy();
virtual void removeOperationCopy();
virtual void moveOperationCopy(const QPointF&);
virtual void rotateOperationCopy(const double&);
//多边形、线段等点选创建的对象需要的函数
virtual void addPoint(const QPointF&) {}
virtual bool endDrawing() { return true; }

View File

@ -6,6 +6,7 @@
enum HandleType
{
T_resize, //调整大小
T_rotate, //旋转
T_editShape //编辑形状
};
@ -20,6 +21,10 @@ enum HandleTag
H_bottom,
H_leftBottom,
H_left, //8
H_rotate_leftTop,
H_rotate_rightTop,
H_rotate_rightBottom,
H_rotate_leftBottom, //12
H_edit
};
@ -39,6 +44,7 @@ public:
void setTag(int ht) { m_tag = ht; }
int getTag() { return m_tag; }
int getSize();
void move(double, double);
protected:

View File

@ -19,7 +19,7 @@ enum SelectorType
ST_moving, //移动
ST_editing, //顶点编辑
ST_scaling, //缩放
ST_rotating, //旋转
ST_rotation, //旋转
};
enum OperationMode
@ -56,10 +56,11 @@ signals:
void setWorkingSelector(SelectorType);
protected:
//静态变量,用于不同类型对象间的成员共享
//静态变量,用于不同类型selector间的成员共享
static OperationMode ms_opMode;
static QPointF ms_ptMouseDown;
static QPointF ms_ptMouseLast;
static double ms_dAngleMouseDownToItem; //鼠标按下时其位置和item中心点形成的夹角
static int ms_nDragHandle; //当前抓取的控制点
SelectorType m_type;

View File

@ -0,0 +1,28 @@
/**
*\file rotationSelector.h
*
*\brief selector
*
*\author dsc
*/
#ifndef ROTATIONSELECTOR_H
#define ROTATIONSELECTOR_H
#include "baseSelector.h"
class RotationSelector : public BaseSelector
{
Q_OBJECT
public:
explicit RotationSelector(QObject *parent = 0);
virtual ~RotationSelector();
public:
void mousePressEvent(QGraphicsSceneMouseEvent*, DesignerScene*);
void mouseMoveEvent(QGraphicsSceneMouseEvent*, DesignerScene*);
void mouseReleaseEvent(QGraphicsSceneMouseEvent*, DesignerScene*);
};
#endif

View File

@ -1,5 +1,8 @@
<RCC>
<qresource prefix="/">
<file>images/checkerboard.png</file>
<file>images/icon_rotate.png</file>
<file>images/icon_rotate2.png</file>
<file>images/icon-rotate3.png</file>
</qresource>
</RCC>

Binary file not shown.

After

Width:  |  Height:  |  Size: 373 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 387 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 347 B

View File

@ -13,6 +13,13 @@ GraphicsBaseItem::GraphicsBaseItem(QGraphicsItem *parent)
pHandle->setTag(i);
m_vecHanle.push_back(pHandle);
}
for(int i = H_rotate_leftTop; i <= H_rotate_leftBottom; i++)
{
ItemControlHandle* pHandle = new ItemControlHandle(this);
pHandle->setType(T_rotate);
pHandle->setTag(i);
m_vecHanle.push_back(pHandle);
}
setFlag(QGraphicsItem::ItemIsMovable, true);
setFlag(QGraphicsItem::ItemIsSelectable, true);
@ -26,43 +33,52 @@ GraphicsBaseItem::~GraphicsBaseItem()
}
void GraphicsBaseItem::createMovingCopy()
void GraphicsBaseItem::createOperationCopy()
{
m_pMovingCopy = new QGraphicsPathItem(this->shape());
m_pMovingCopy->setPen(Qt::DashLine);
m_pMovingCopy->setPos(this->pos());
m_pMovingCopy->setTransformOriginPoint(this->transformOriginPoint());
m_pMovingCopy->setTransform(this->transform());
m_pMovingCopy->setRotation(this->rotation());
m_pMovingCopy->setScale(this->scale());
m_pMovingCopy->setZValue(this->zValue());
m_pOperationCopy = new QGraphicsPathItem(this->shape());
m_pOperationCopy->setPen(Qt::DashLine);
m_pOperationCopy->setPos(this->pos());
m_pOperationCopy->setTransformOriginPoint(this->transformOriginPoint());
m_pOperationCopy->setTransform(this->transform());
m_pOperationCopy->setRotation(this->rotation());
m_pOperationCopy->setScale(this->scale());
m_pOperationCopy->setZValue(this->zValue());
QGraphicsScene* scene = this->scene();
if(scene && m_pMovingCopy)
if(scene && m_pOperationCopy)
{
scene->addItem(m_pMovingCopy);
scene->addItem(m_pOperationCopy);
m_movingIniPos = this->pos();
}
}
void GraphicsBaseItem::removeMovingCopy()
void GraphicsBaseItem::removeOperationCopy()
{
QGraphicsScene* scene = this->scene();
if(scene && m_pMovingCopy)
if(scene && m_pOperationCopy)
{
this->setPos(m_pMovingCopy->pos()); //本体先移动到副本的位置
scene->removeItem(m_pMovingCopy);
delete m_pMovingCopy;
m_pMovingCopy = nullptr;
if(this->pos() != m_pOperationCopy->pos())
this->setPos(m_pOperationCopy->pos()); //本体移动到副本的位置
if(this->rotation() != m_pOperationCopy->rotation())
this->setRotation(m_pOperationCopy->rotation()); //本体旋转至副本的角度
scene->removeItem(m_pOperationCopy);
delete m_pOperationCopy;
m_pOperationCopy = nullptr;
}
}
void GraphicsBaseItem::moveMovingCopy(const QPointF& distance)
void GraphicsBaseItem::moveOperationCopy(const QPointF& distance)
{
if(m_pMovingCopy)
m_pMovingCopy->setPos(m_movingIniPos + distance);
if(m_pOperationCopy)
m_pOperationCopy->setPos(m_movingIniPos + distance);
}
void GraphicsBaseItem::rotateOperationCopy(const double& dAngle)
{
if(m_pOperationCopy)
m_pOperationCopy->setRotation(dAngle);
}
QVariant GraphicsBaseItem::itemChange(QGraphicsItem::GraphicsItemChange change, const QVariant& value)
{

View File

@ -105,7 +105,7 @@ void GraphicPolygonItem::move(const QPointF& point)
void GraphicPolygonItem::editShape(int nHandle,const QPointF& ptMouse)
{
QPointF pt = mapFromScene(ptMouse);
m_points[nHandle - H_left - 1] = pt;
m_points[nHandle - H_rotate_leftBottom - 1] = pt;
prepareGeometryChange();
m_boundingRect = m_points.boundingRect();
m_dWidth = m_boundingRect.width();

View File

@ -30,6 +30,12 @@ void ItemControlHandle::paint(QPainter* painter, const QStyleOptionGraphicsItem*
painter->setBrush(Qt::white);
painter->drawRect(rect());
}
else if(m_type==T_rotate)
{
painter->setPen(Qt::NoPen);
painter->setBrush(Qt::NoBrush);
painter->drawRect(rect());
}
else if(m_type==T_editShape)
{
painter->setBrush(Qt::green);
@ -47,6 +53,12 @@ void ItemControlHandle::hoverLeaveEvent(QGraphicsSceneHoverEvent* event)
QGraphicsRectItem::hoverLeaveEvent(event);
}
int ItemControlHandle::getSize()
{
int nSize = HNDLE_SIZE;
return nSize;
}
void ItemControlHandle::move(double x, double y)
{
setPos(x, y);

View File

@ -6,6 +6,7 @@
QPointF BaseSelector::ms_ptMouseDown(0.0,0.0);
QPointF BaseSelector::ms_ptMouseLast(0.0,0.0);
double BaseSelector::ms_dAngleMouseDownToItem = 0.0;
int BaseSelector::ms_nDragHandle = 0;
BaseSelector::BaseSelector(QObject *parent)
@ -46,7 +47,19 @@ void BaseSelector::mousePressEvent(QGraphicsSceneMouseEvent* event, DesignerScen
m_opMode = OM_scale;
emit setWorkingSelector(ST_scaling);
}
else if(ms_nDragHandle > H_left) //编辑控制点上
else if(ms_nDragHandle >= H_rotate_leftTop && ms_nDragHandle <= H_rotate_leftBottom) //在旋转控制点上
{
m_opMode = OM_rotate;
//计算夹角
QPointF originPoint = item->mapToScene(item->boundingRect().center());
double dLengthY = ms_ptMouseLast.y() - originPoint.y();
double dLengthX = ms_ptMouseLast.x() - originPoint.x();
ms_dAngleMouseDownToItem = atan2(dLengthY, dLengthX) * 180 / M_PI;
//创建副本
item->createOperationCopy();
emit setWorkingSelector(ST_rotation);
}
else if(ms_nDragHandle > H_rotate_leftBottom) //编辑控制点上
{
m_opMode = OM_edit;
setCursor(scene, Qt::ClosedHandCursor);
@ -67,12 +80,13 @@ void BaseSelector::mousePressEvent(QGraphicsSceneMouseEvent* event, DesignerScen
setCursor(scene, Qt::ClosedHandCursor);
}
if(m_opMode == OM_move)
if(m_opMode == OM_move) //可以多个选中同时移动
{
for(int n = 0; n < items.size(); n++)
{
//创建副本
GraphicsBaseItem* item = qgraphicsitem_cast<GraphicsBaseItem*>(items.at(n));
item->createMovingCopy();
item->createOperationCopy();
}
}
else if(m_opMode == OM_none)
@ -132,6 +146,15 @@ void BaseSelector::mouseMoveEvent(QGraphicsSceneMouseEvent* event, DesignerScene
case H_left:
setCursor(scene, Qt::SizeHorCursor);
break;
case H_rotate_leftTop:
case H_rotate_rightTop:
case H_rotate_rightBottom:
case H_rotate_leftBottom:
{
int nSize = 24;
QCursor rotateCursor = QCursor(QPixmap(":/images/icon_rotate2.png").scaled(nSize, nSize, Qt::KeepAspectRatio, Qt::SmoothTransformation));
setCursor(scene, rotateCursor);
}
default:
break;
}

View File

@ -27,7 +27,7 @@ void MovingSelector::mouseMoveEvent(QGraphicsSceneMouseEvent* event, DesignerSce
{
GraphicsBaseItem* item = qgraphicsitem_cast<GraphicsBaseItem*>(items.at(n));
if(item)
item->moveMovingCopy(ms_ptMouseLast - ms_ptMouseDown);
item->moveOperationCopy(ms_ptMouseLast - ms_ptMouseDown);
}
}
@ -38,7 +38,7 @@ void MovingSelector::mouseReleaseEvent(QGraphicsSceneMouseEvent* event, Designer
{
GraphicsBaseItem* item = qgraphicsitem_cast<GraphicsBaseItem*>(items.at(n));
if(item)
item->removeMovingCopy();
item->removeOperationCopy();
}
setCursor(scene, Qt::ArrowCursor);

View File

@ -0,0 +1,60 @@
#include "util/rotationSelector.h"
#include <QGraphicsSceneMouseEvent>
#include <QGraphicsView>
#include <graphicsItem/graphicsBaseItem.h>
RotationSelector::RotationSelector(QObject *parent)
: BaseSelector(parent)
{
m_type = ST_rotation;
}
RotationSelector::~RotationSelector()
{
}
void RotationSelector::mousePressEvent(QGraphicsSceneMouseEvent* event, DesignerScene* scene)
{
}
void RotationSelector::mouseMoveEvent(QGraphicsSceneMouseEvent* event, DesignerScene* scene)
{
ms_ptMouseLast = event->scenePos();
QList<QGraphicsItem *> items = scene->selectedItems();
if (items.count() == 1)
{
GraphicsBaseItem* item = qgraphicsitem_cast<GraphicsBaseItem*>(items.first());
if(item)
{
//计算夹角
QPointF originPoint = item->mapToScene(item->boundingRect().center());
double dLengthY = ms_ptMouseLast.y() - originPoint.y();
double dLengthX = ms_ptMouseLast.x() - originPoint.x();
double dAngleMouseToItem = atan2(dLengthY, dLengthX) * 180 / M_PI;
double rotationAngle = item->rotation() + (dAngleMouseToItem - ms_dAngleMouseDownToItem);
if (rotationAngle > 360)
rotationAngle -= 360;
if (rotationAngle < -360)
rotationAngle += 360;
item->rotateOperationCopy(rotationAngle);
}
}
}
void RotationSelector::mouseReleaseEvent(QGraphicsSceneMouseEvent* event, DesignerScene* scene)
{
QList<QGraphicsItem *> items = scene->selectedItems();
for(int n = 0; n < items.size(); n++)
{
GraphicsBaseItem* item = qgraphicsitem_cast<GraphicsBaseItem*>(items.at(n));
if(item)
item->removeOperationCopy();
}
ms_nDragHandle = H_none;
setCursor(scene, Qt::ArrowCursor);
emit setWorkingSelector(ST_base);
}

View File

@ -1,6 +1,7 @@
#include "util/selectorManager.h"
#include "util/creatingSelector.h"
#include "util/movingSelector.h"
#include "util/rotationSelector.h"
#include "util/scalingSelector.h"
#include "util/editingSelector.h"
@ -21,6 +22,9 @@ SelectorManager::SelectorManager(QObject *parent)
MovingSelector* movingSelector = new MovingSelector(this);
connect(movingSelector, SIGNAL(setWorkingSelector(SelectorType)), this, SLOT(onSignal_setWorkingSelector(SelectorType)));
m_vecSelectors.push_back(movingSelector);
RotationSelector* rotationSelector = new RotationSelector(this);
connect(rotationSelector, SIGNAL(setWorkingSelector(SelectorType)), this, SLOT(onSignal_setWorkingSelector(SelectorType)));
m_vecSelectors.push_back(rotationSelector);
ScalingSelector* scalingSelector = new ScalingSelector(this);
connect(scalingSelector, SIGNAL(setWorkingSelector(SelectorType)), this, SLOT(onSignal_setWorkingSelector(SelectorType)));
m_vecSelectors.push_back(scalingSelector);

View File

@ -6,8 +6,8 @@
<rect>
<x>0</x>
<y>0</y>
<width>1612</width>
<height>1016</height>
<width>1696</width>
<height>1079</height>
</rect>
</property>
<property name="windowTitle">
@ -19,7 +19,7 @@
<rect>
<x>0</x>
<y>0</y>
<width>1612</width>
<width>1696</width>
<height>33</height>
</rect>
</property>