2024-12-03 20:07:25 +08:00
|
|
|
|
#include "graphicsItem/graphicsItemGroup.h"
|
2024-12-13 18:08:00 +08:00
|
|
|
|
#include "graphicsItem/handleRect.h"
|
2024-12-03 20:07:25 +08:00
|
|
|
|
#include <QGraphicsScene>
|
|
|
|
|
|
#include <QPainter>
|
|
|
|
|
|
#include <QStyleOption>
|
|
|
|
|
|
#include <QTimer>
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
GraphicsItemGroup::GraphicsItemGroup(QGraphicsItem *parent)
|
|
|
|
|
|
: AbstractShapeType<QGraphicsItemGroup>(parent)
|
|
|
|
|
|
{
|
|
|
|
|
|
m_type = T_group;
|
|
|
|
|
|
|
|
|
|
|
|
m_boundingRect = QRectF();
|
|
|
|
|
|
m_lastBoudingRect = QGraphicsItemGroup::boundingRect();
|
|
|
|
|
|
|
|
|
|
|
|
//初始化缩放操作用的handle
|
|
|
|
|
|
//m_vecHanle.reserve(H_left);
|
|
|
|
|
|
for(int i = H_leftTop; i <= H_left; i++)
|
|
|
|
|
|
{
|
2024-12-13 18:08:00 +08:00
|
|
|
|
ItemControlHandle* pHandle = new HandleRect(this);
|
2024-12-03 20:07:25 +08:00
|
|
|
|
pHandle->setType(T_resize);
|
|
|
|
|
|
pHandle->setTag(i);
|
|
|
|
|
|
m_vecHanle.insert(i-1,pHandle);
|
|
|
|
|
|
}
|
|
|
|
|
|
for(int i = H_rotate_leftTop; i <= H_rotate_leftBottom; i++)
|
|
|
|
|
|
{
|
2024-12-13 18:08:00 +08:00
|
|
|
|
ItemControlHandle* pHandle = new HandleRect(this);
|
2024-12-03 20:07:25 +08:00
|
|
|
|
pHandle->setType(T_rotate);
|
|
|
|
|
|
pHandle->setTag(i);
|
|
|
|
|
|
m_vecHanle.insert(i-1,pHandle);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
setFlag(QGraphicsItem::ItemIsMovable, true);
|
|
|
|
|
|
setFlag(QGraphicsItem::ItemIsSelectable, true);
|
|
|
|
|
|
setFlag(QGraphicsItem::ItemSendsGeometryChanges, true);
|
|
|
|
|
|
setAcceptHoverEvents(true);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
GraphicsItemGroup::~GraphicsItemGroup()
|
|
|
|
|
|
{
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
QPainterPath GraphicsItemGroup::shape()
|
|
|
|
|
|
{
|
|
|
|
|
|
QPainterPath path;
|
|
|
|
|
|
path.addRect(m_boundingRect);
|
|
|
|
|
|
return path;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void GraphicsItemGroup::paint(QPainter* painter, const QStyleOptionGraphicsItem* option, QWidget* widget)
|
|
|
|
|
|
{
|
|
|
|
|
|
if (option->state & QStyle::State_Selected) //是选中状态,绘制选中框
|
|
|
|
|
|
{
|
|
|
|
|
|
int nPenWidth = 1;
|
|
|
|
|
|
painter->setPen(QPen(QColor(70,70,70), nPenWidth, Qt::DashLine)); //蓝色的外框
|
|
|
|
|
|
painter->setBrush(Qt::NoBrush);
|
|
|
|
|
|
painter->drawRect(m_boundingRect_selected);
|
|
|
|
|
|
|
|
|
|
|
|
//绘制变换原点
|
|
|
|
|
|
/*QPointF originPoint = transformOriginPoint();
|
|
|
|
|
|
//qDebug() << "originPoint:" << originPoint << " boundingRect:" << m_boundingRect;
|
|
|
|
|
|
painter->setBrush(Qt::red);
|
|
|
|
|
|
painter->drawEllipse(QPointF(0,0), 4, 4);
|
|
|
|
|
|
painter->setBrush(Qt::blue);
|
|
|
|
|
|
painter->drawEllipse(originPoint, 4, 4);*/
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void GraphicsItemGroup::contextMenuEvent(QGraphicsSceneContextMenuEvent* event)
|
|
|
|
|
|
{
|
|
|
|
|
|
Q_UNUSED(event);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
QVariant GraphicsItemGroup::itemChange(QGraphicsItem::GraphicsItemChange change, const QVariant& value)
|
|
|
|
|
|
{
|
|
|
|
|
|
if (change == QGraphicsItem::ItemSelectedHasChanged)
|
|
|
|
|
|
{
|
|
|
|
|
|
QGraphicsItemGroup *group = dynamic_cast<QGraphicsItemGroup *>(parentItem());
|
|
|
|
|
|
if(!group)
|
|
|
|
|
|
setHandleVisible(value.toBool());
|
|
|
|
|
|
else //在某一组群中,由组群展示是否选中,自身不做展示
|
|
|
|
|
|
{
|
|
|
|
|
|
setSelected(false);
|
|
|
|
|
|
return QVariant::fromValue<bool>(false);
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
return QGraphicsItemGroup::itemChange(change, value);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void GraphicsItemGroup::syncRotationDataFromParent(const double& data)
|
|
|
|
|
|
{
|
|
|
|
|
|
/*m_dSyncRotationByParent += data;
|
|
|
|
|
|
//让角度保持在正负180的区间,也就是上下两个半圈,这样易于象限判断
|
|
|
|
|
|
if (m_dSyncRotationByParent > 180)
|
|
|
|
|
|
m_dSyncRotationByParent -= 360;
|
|
|
|
|
|
if (m_dSyncRotationByParent < -180)
|
|
|
|
|
|
m_dSyncRotationByParent += 360;
|
|
|
|
|
|
//同步给子项
|
|
|
|
|
|
foreach (QGraphicsItem* item, childItems())
|
|
|
|
|
|
{
|
|
|
|
|
|
if(qgraphicsitem_cast<ItemControlHandle*>(item))
|
|
|
|
|
|
continue;
|
|
|
|
|
|
|
|
|
|
|
|
AbstractShape* shape = qgraphicsitem_cast<AbstractShape*>(item);
|
|
|
|
|
|
if(shape && shape->getType()==T_group)
|
|
|
|
|
|
{
|
|
|
|
|
|
GraphicsItemGroup *group = qgraphicsitem_cast<GraphicsItemGroup *>(item);
|
|
|
|
|
|
if(group)
|
|
|
|
|
|
group->syncRotationDataFromParent(data);
|
|
|
|
|
|
}
|
|
|
|
|
|
else
|
|
|
|
|
|
{
|
|
|
|
|
|
GraphicsBaseItem *baseItem = qgraphicsitem_cast<GraphicsBaseItem*>(item);
|
|
|
|
|
|
if (baseItem)
|
|
|
|
|
|
baseItem->syncRotationDataFromParent(data);
|
|
|
|
|
|
}
|
|
|
|
|
|
}*/
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void GraphicsItemGroup::updateCoordinate() //当执行了resie和editShape函数后,boundingRect发生了变换,需要将item的原点(以中心点为原点)校准至boundingRect.center()
|
|
|
|
|
|
{
|
|
|
|
|
|
if (!parentItem())
|
|
|
|
|
|
{
|
|
|
|
|
|
if (m_boundingRect.isNull())
|
|
|
|
|
|
{
|
|
|
|
|
|
m_boundingRect = QGraphicsItemGroup::boundingRect();
|
|
|
|
|
|
m_dWidth = m_boundingRect.width();
|
|
|
|
|
|
m_dHeight = m_boundingRect.height();
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
//因为group包含子item,boundingRect会根据子item自动计算生成,所以不再通过重设boundingRect(中心和原点重合)重合的方式,因为此种方式需要子item做各种同步计算
|
|
|
|
|
|
//最简单的方式是,每次boundingRect发生变化(缩放)后重新设置变换中心,但是会出现漂移(因为item只存储旋转角度数据,每帧都根据角度进行重绘),具体见开发学习笔记,消除这个漂移即可
|
|
|
|
|
|
prepareGeometryChange();
|
|
|
|
|
|
//具体计算
|
|
|
|
|
|
double dAngle = qDegreesToRadians(rotation());
|
|
|
|
|
|
QPointF centerPt = m_boundingRect.center();
|
|
|
|
|
|
QPointF originPt = transformOriginPoint();
|
|
|
|
|
|
QPointF targetPt = QPointF(0, 0);
|
|
|
|
|
|
targetPt.setX(originPt.x() + qCos(dAngle)*(centerPt.x() - originPt.x()) - qSin(dAngle)*(centerPt.y() - originPt.y()));
|
|
|
|
|
|
targetPt.setY(originPt.y() + qSin(dAngle)*(centerPt.x() - originPt.x()) + qCos(dAngle)*(centerPt.y() - originPt.y()));
|
|
|
|
|
|
QPointF delta = targetPt - centerPt;
|
|
|
|
|
|
//m_boundingRect.adjust(delta.x(), delta.y(), delta.x(), delta.y());
|
|
|
|
|
|
setTransformOriginPoint(m_boundingRect.center());
|
|
|
|
|
|
if(dAngle != 0)
|
|
|
|
|
|
moveBy(delta.x(), delta.y());
|
|
|
|
|
|
|
|
|
|
|
|
//QTimer::singleShot(2000,[&](){moveBy(-delta.x(), -delta.y());});
|
|
|
|
|
|
|
|
|
|
|
|
updateHandles();
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
//调用该组内所有item(过滤handle)相关函数
|
|
|
|
|
|
foreach (QGraphicsItem *item, childItems())
|
|
|
|
|
|
{
|
|
|
|
|
|
GraphicsBaseItem *baseItem = qgraphicsitem_cast<GraphicsBaseItem*>(item);
|
|
|
|
|
|
if (baseItem && !qgraphicsitem_cast<ItemControlHandle*>(baseItem))
|
|
|
|
|
|
{
|
|
|
|
|
|
baseItem->updateCoordinate();
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
m_lastBoudingRect = m_boundingRect;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void GraphicsItemGroup::resize(int nHandle,double dSX, double dSY, const QPointF& basePoint)
|
|
|
|
|
|
{
|
|
|
|
|
|
switch (nHandle)
|
|
|
|
|
|
{
|
|
|
|
|
|
case H_left:
|
|
|
|
|
|
case H_right:
|
|
|
|
|
|
dSY = 1; //拖拽的是左点右点,为水平缩放,忽略垂直变化
|
|
|
|
|
|
break;
|
|
|
|
|
|
case H_top:
|
|
|
|
|
|
case H_bottom:
|
|
|
|
|
|
dSX = 1; //拖拽的是顶点底点,为垂直缩放,忽略水平变化
|
|
|
|
|
|
break;
|
|
|
|
|
|
default:
|
|
|
|
|
|
break;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
QTransform trans;
|
|
|
|
|
|
//缩放是以图元变换原点为基准,所以每帧都先移动移动到想要的基准点,缩放之后再移回
|
|
|
|
|
|
trans.translate(basePoint.x(), basePoint.y());
|
|
|
|
|
|
trans.scale(dSX, dSY);
|
|
|
|
|
|
trans.translate(-basePoint.x(), -basePoint.y());
|
|
|
|
|
|
|
|
|
|
|
|
prepareGeometryChange();
|
|
|
|
|
|
m_boundingRect = trans.mapRect(m_lastBoudingRect);
|
|
|
|
|
|
m_dWidth = m_boundingRect.width();
|
|
|
|
|
|
m_dHeight = m_boundingRect.height();
|
|
|
|
|
|
updateHandles();
|
|
|
|
|
|
|
|
|
|
|
|
//调用该组内所有item(过滤handle)相关函数
|
|
|
|
|
|
foreach (QGraphicsItem *item, childItems())
|
|
|
|
|
|
{
|
|
|
|
|
|
GraphicsBaseItem *baseItem = qgraphicsitem_cast<GraphicsBaseItem*>(item);
|
|
|
|
|
|
if (baseItem && !qgraphicsitem_cast<ItemControlHandle*>(baseItem))
|
|
|
|
|
|
{
|
|
|
|
|
|
baseItem->resize(nHandle, dSX, dSY, baseItem->mapFromParent(basePoint));
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void GraphicsItemGroup::createOperationCopy()
|
|
|
|
|
|
{
|
|
|
|
|
|
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_pOperationCopy)
|
|
|
|
|
|
{
|
|
|
|
|
|
scene->addItem(m_pOperationCopy);
|
|
|
|
|
|
m_movingIniPos = this->pos();
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void GraphicsItemGroup::removeOperationCopy()
|
|
|
|
|
|
{
|
|
|
|
|
|
QGraphicsScene* scene = this->scene();
|
|
|
|
|
|
if(scene && m_pOperationCopy)
|
|
|
|
|
|
{
|
|
|
|
|
|
if(this->pos() != m_pOperationCopy->pos())
|
|
|
|
|
|
this->setPos(m_pOperationCopy->pos()); //本体移动到副本的位置
|
|
|
|
|
|
if(this->rotation() != m_pOperationCopy->rotation())
|
|
|
|
|
|
{
|
|
|
|
|
|
double dAngle = m_pOperationCopy->rotation();
|
|
|
|
|
|
this->setRotation(dAngle); //本体旋转至副本的角度
|
|
|
|
|
|
//子item的旋转数据并不会和所在组同步,需要手动同步
|
|
|
|
|
|
foreach (QGraphicsItem* item, childItems())
|
|
|
|
|
|
{
|
|
|
|
|
|
if(qgraphicsitem_cast<ItemControlHandle*>(item))
|
|
|
|
|
|
continue;
|
|
|
|
|
|
|
|
|
|
|
|
// AbstractShape* shape = qgraphicsitem_cast<AbstractShape*>(item);
|
|
|
|
|
|
// if(shape && shape->getType()==T_group)
|
|
|
|
|
|
// {
|
|
|
|
|
|
// GraphicsItemGroup *group = qgraphicsitem_cast<GraphicsItemGroup *>(item);
|
|
|
|
|
|
// if(group)
|
|
|
|
|
|
// group->syncRotationDataFromParent(dAngle);
|
|
|
|
|
|
// }
|
|
|
|
|
|
// else
|
|
|
|
|
|
{
|
|
|
|
|
|
GraphicsBaseItem *baseItem = qgraphicsitem_cast<GraphicsBaseItem*>(item);
|
|
|
|
|
|
if (baseItem)
|
|
|
|
|
|
baseItem->syncRotationDataFromParent(dAngle);
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
scene->removeItem(m_pOperationCopy);
|
|
|
|
|
|
delete m_pOperationCopy;
|
|
|
|
|
|
m_pOperationCopy = nullptr;
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void GraphicsItemGroup::moveOperationCopy(const QPointF& distance)
|
|
|
|
|
|
{
|
|
|
|
|
|
if(m_pOperationCopy)
|
|
|
|
|
|
m_pOperationCopy->setPos(m_movingIniPos + distance);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void GraphicsItemGroup::rotateOperationCopy(const double& dAngle)
|
|
|
|
|
|
{
|
|
|
|
|
|
if(m_pOperationCopy)
|
|
|
|
|
|
{
|
|
|
|
|
|
m_pOperationCopy->setRotation(dAngle);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void GraphicsItemGroup::addItems(const QList<QGraphicsItem*>& items)
|
|
|
|
|
|
{
|
|
|
|
|
|
foreach (QGraphicsItem *item, items)
|
|
|
|
|
|
{
|
|
|
|
|
|
item->setSelected(false);
|
|
|
|
|
|
addToGroup(item);
|
|
|
|
|
|
m_listItem.push_back(item);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
updateCoordinate();
|
|
|
|
|
|
}
|