实现图元的旋转操作,通过鼠标移动到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/baseSelector.h
include/util/creatingSelector.h include/util/creatingSelector.h
include/util/movingSelector.h include/util/movingSelector.h
include/util/rotationSelector.h
include/util/scalingSelector.h include/util/scalingSelector.h
include/util/editingSelector.h include/util/editingSelector.h
include/util/selectorManager.h include/util/selectorManager.h
@ -65,6 +66,7 @@ set(CPP_SOURCE_FILES
source/util/baseSelector.cpp source/util/baseSelector.cpp
source/util/creatingSelector.cpp source/util/creatingSelector.cpp
source/util/movingSelector.cpp source/util/movingSelector.cpp
source/util/rotationSelector.cpp
source/util/scalingSelector.cpp source/util/scalingSelector.cpp
source/util/editingSelector.cpp source/util/editingSelector.cpp
source/util/selectorManager.cpp source/util/selectorManager.cpp

View File

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

View File

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

View File

@ -19,7 +19,7 @@ enum SelectorType
ST_moving, //移动 ST_moving, //移动
ST_editing, //顶点编辑 ST_editing, //顶点编辑
ST_scaling, //缩放 ST_scaling, //缩放
ST_rotating, //旋转 ST_rotation, //旋转
}; };
enum OperationMode enum OperationMode
@ -56,10 +56,11 @@ signals:
void setWorkingSelector(SelectorType); void setWorkingSelector(SelectorType);
protected: protected:
//静态变量,用于不同类型对象间的成员共享 //静态变量,用于不同类型selector间的成员共享
static OperationMode ms_opMode; static OperationMode ms_opMode;
static QPointF ms_ptMouseDown; static QPointF ms_ptMouseDown;
static QPointF ms_ptMouseLast; static QPointF ms_ptMouseLast;
static double ms_dAngleMouseDownToItem; //鼠标按下时其位置和item中心点形成的夹角
static int ms_nDragHandle; //当前抓取的控制点 static int ms_nDragHandle; //当前抓取的控制点
SelectorType m_type; 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> <RCC>
<qresource prefix="/"> <qresource prefix="/">
<file>images/checkerboard.png</file> <file>images/checkerboard.png</file>
<file>images/icon_rotate.png</file>
<file>images/icon_rotate2.png</file>
<file>images/icon-rotate3.png</file>
</qresource> </qresource>
</RCC> </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); pHandle->setTag(i);
m_vecHanle.push_back(pHandle); 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::ItemIsMovable, true);
setFlag(QGraphicsItem::ItemIsSelectable, true); setFlag(QGraphicsItem::ItemIsSelectable, true);
@ -26,43 +33,52 @@ GraphicsBaseItem::~GraphicsBaseItem()
} }
void GraphicsBaseItem::createMovingCopy() void GraphicsBaseItem::createOperationCopy()
{ {
m_pMovingCopy = new QGraphicsPathItem(this->shape()); m_pOperationCopy = new QGraphicsPathItem(this->shape());
m_pMovingCopy->setPen(Qt::DashLine); m_pOperationCopy->setPen(Qt::DashLine);
m_pMovingCopy->setPos(this->pos()); m_pOperationCopy->setPos(this->pos());
m_pMovingCopy->setTransformOriginPoint(this->transformOriginPoint()); m_pOperationCopy->setTransformOriginPoint(this->transformOriginPoint());
m_pMovingCopy->setTransform(this->transform()); m_pOperationCopy->setTransform(this->transform());
m_pMovingCopy->setRotation(this->rotation()); m_pOperationCopy->setRotation(this->rotation());
m_pMovingCopy->setScale(this->scale()); m_pOperationCopy->setScale(this->scale());
m_pMovingCopy->setZValue(this->zValue()); m_pOperationCopy->setZValue(this->zValue());
QGraphicsScene* scene = this->scene(); QGraphicsScene* scene = this->scene();
if(scene && m_pMovingCopy) if(scene && m_pOperationCopy)
{ {
scene->addItem(m_pMovingCopy); scene->addItem(m_pOperationCopy);
m_movingIniPos = this->pos(); m_movingIniPos = this->pos();
} }
} }
void GraphicsBaseItem::removeMovingCopy() void GraphicsBaseItem::removeOperationCopy()
{ {
QGraphicsScene* scene = this->scene(); QGraphicsScene* scene = this->scene();
if(scene && m_pMovingCopy) if(scene && m_pOperationCopy)
{ {
this->setPos(m_pMovingCopy->pos()); //本体先移动到副本的位置 if(this->pos() != m_pOperationCopy->pos())
scene->removeItem(m_pMovingCopy); this->setPos(m_pOperationCopy->pos()); //本体移动到副本的位置
delete m_pMovingCopy; if(this->rotation() != m_pOperationCopy->rotation())
m_pMovingCopy = nullptr; 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) if(m_pOperationCopy)
m_pMovingCopy->setPos(m_movingIniPos + distance); 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) 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) void GraphicPolygonItem::editShape(int nHandle,const QPointF& ptMouse)
{ {
QPointF pt = mapFromScene(ptMouse); QPointF pt = mapFromScene(ptMouse);
m_points[nHandle - H_left - 1] = pt; m_points[nHandle - H_rotate_leftBottom - 1] = pt;
prepareGeometryChange(); prepareGeometryChange();
m_boundingRect = m_points.boundingRect(); m_boundingRect = m_points.boundingRect();
m_dWidth = m_boundingRect.width(); m_dWidth = m_boundingRect.width();

View File

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

View File

@ -6,6 +6,7 @@
QPointF BaseSelector::ms_ptMouseDown(0.0,0.0); QPointF BaseSelector::ms_ptMouseDown(0.0,0.0);
QPointF BaseSelector::ms_ptMouseLast(0.0,0.0); QPointF BaseSelector::ms_ptMouseLast(0.0,0.0);
double BaseSelector::ms_dAngleMouseDownToItem = 0.0;
int BaseSelector::ms_nDragHandle = 0; int BaseSelector::ms_nDragHandle = 0;
BaseSelector::BaseSelector(QObject *parent) BaseSelector::BaseSelector(QObject *parent)
@ -46,7 +47,19 @@ void BaseSelector::mousePressEvent(QGraphicsSceneMouseEvent* event, DesignerScen
m_opMode = OM_scale; m_opMode = OM_scale;
emit setWorkingSelector(ST_scaling); 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; m_opMode = OM_edit;
setCursor(scene, Qt::ClosedHandCursor); setCursor(scene, Qt::ClosedHandCursor);
@ -67,12 +80,13 @@ void BaseSelector::mousePressEvent(QGraphicsSceneMouseEvent* event, DesignerScen
setCursor(scene, Qt::ClosedHandCursor); setCursor(scene, Qt::ClosedHandCursor);
} }
if(m_opMode == OM_move) if(m_opMode == OM_move) //可以多个选中同时移动
{ {
for(int n = 0; n < items.size(); n++) for(int n = 0; n < items.size(); n++)
{ {
//创建副本
GraphicsBaseItem* item = qgraphicsitem_cast<GraphicsBaseItem*>(items.at(n)); GraphicsBaseItem* item = qgraphicsitem_cast<GraphicsBaseItem*>(items.at(n));
item->createMovingCopy(); item->createOperationCopy();
} }
} }
else if(m_opMode == OM_none) else if(m_opMode == OM_none)
@ -132,6 +146,15 @@ void BaseSelector::mouseMoveEvent(QGraphicsSceneMouseEvent* event, DesignerScene
case H_left: case H_left:
setCursor(scene, Qt::SizeHorCursor); setCursor(scene, Qt::SizeHorCursor);
break; 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: default:
break; break;
} }

View File

@ -27,7 +27,7 @@ void MovingSelector::mouseMoveEvent(QGraphicsSceneMouseEvent* event, DesignerSce
{ {
GraphicsBaseItem* item = qgraphicsitem_cast<GraphicsBaseItem*>(items.at(n)); GraphicsBaseItem* item = qgraphicsitem_cast<GraphicsBaseItem*>(items.at(n));
if(item) 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)); GraphicsBaseItem* item = qgraphicsitem_cast<GraphicsBaseItem*>(items.at(n));
if(item) if(item)
item->removeMovingCopy(); item->removeOperationCopy();
} }
setCursor(scene, Qt::ArrowCursor); 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/selectorManager.h"
#include "util/creatingSelector.h" #include "util/creatingSelector.h"
#include "util/movingSelector.h" #include "util/movingSelector.h"
#include "util/rotationSelector.h"
#include "util/scalingSelector.h" #include "util/scalingSelector.h"
#include "util/editingSelector.h" #include "util/editingSelector.h"
@ -21,6 +22,9 @@ SelectorManager::SelectorManager(QObject *parent)
MovingSelector* movingSelector = new MovingSelector(this); MovingSelector* movingSelector = new MovingSelector(this);
connect(movingSelector, SIGNAL(setWorkingSelector(SelectorType)), this, SLOT(onSignal_setWorkingSelector(SelectorType))); connect(movingSelector, SIGNAL(setWorkingSelector(SelectorType)), this, SLOT(onSignal_setWorkingSelector(SelectorType)));
m_vecSelectors.push_back(movingSelector); 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); ScalingSelector* scalingSelector = new ScalingSelector(this);
connect(scalingSelector, SIGNAL(setWorkingSelector(SelectorType)), this, SLOT(onSignal_setWorkingSelector(SelectorType))); connect(scalingSelector, SIGNAL(setWorkingSelector(SelectorType)), this, SLOT(onSignal_setWorkingSelector(SelectorType)));
m_vecSelectors.push_back(scalingSelector); m_vecSelectors.push_back(scalingSelector);

View File

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