diff --git a/CMakeLists.txt b/CMakeLists.txt index ad07a3b..5782569 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -51,6 +51,7 @@ set(H_HEADER_FILES include/graphicsItem/itemControlHandle.h include/graphicsItem/graphicsBaseItem.h include/graphicsItem/graphicsRectItem.h + include/graphicsItem/graphicsPolygonItem.h ) set(CPP_SOURCE_FILES source/main.cpp @@ -71,6 +72,7 @@ set(CPP_SOURCE_FILES source/graphicsItem/itemControlHandle.cpp source/graphicsItem/graphicsBaseItem.cpp source/graphicsItem/graphicsRectItem.cpp + source/graphicsItem/graphicsPolygonItem.cpp ) set(UI_FILES ui/mainwindow.ui diff --git a/include/graphicsItem/graphicsBaseItem.h b/include/graphicsItem/graphicsBaseItem.h index 0f9a7d6..9852d00 100644 --- a/include/graphicsItem/graphicsBaseItem.h +++ b/include/graphicsItem/graphicsBaseItem.h @@ -72,9 +72,9 @@ public: } //移动副本相关 - virtual void createMovingCopy() {}; - virtual void removeMovingCopy() {}; - virtual void moveMovingCopy(const QPointF&) {}; + virtual void createMovingCopy() {} + virtual void removeMovingCopy() {} + virtual void moveMovingCopy(const QPointF&) {} virtual void resize(int,double, double, const QPointF&) {} virtual void move(const QPointF&) {} @@ -83,6 +83,7 @@ public: virtual void updateCoordinate() {} //handle相关 + virtual int handleCount() { return m_vecHanle.count(); } virtual void setHandleVisible(bool bVisible) { for(auto it = m_vecHanle.begin(); it != m_vecHanle.end(); it++) @@ -198,6 +199,9 @@ public: virtual void createMovingCopy(); virtual void removeMovingCopy(); virtual void moveMovingCopy(const QPointF&); + //多边形、线段等点选创建的对象需要的函数 + virtual void addPoint(const QPointF&) {} + virtual bool endDrawing() { return true; } protected: virtual QVariant itemChange(QGraphicsItem::GraphicsItemChange, const QVariant&); diff --git a/include/graphicsItem/graphicsPolygonItem.h b/include/graphicsItem/graphicsPolygonItem.h new file mode 100644 index 0000000..a76f04e --- /dev/null +++ b/include/graphicsItem/graphicsPolygonItem.h @@ -0,0 +1,33 @@ +#ifndef GRAPHICSPOLYGONITEM_H +#define GRAPHICSPOLYGONITEM_H + +#include "graphicsBaseItem.h" + +class GraphicPolygonItem : public GraphicsBaseItem +{ +public: + GraphicPolygonItem(QGraphicsItem *parent = 0); + virtual ~GraphicPolygonItem(); + + void resize(int,double, double, const QPointF&); + void updateCoordinate(); + void move(const QPointF&); + void editShape(int, const QPointF&); + + void addPoint(const QPointF&); + bool endDrawing(); + QPolygonF getPoints(void) { return m_points; } + +protected: + virtual QPainterPath shape(); + virtual QRectF boundingRect(); + virtual void paint(QPainter*, const QStyleOptionGraphicsItem*, QWidget*); + +private: + virtual void updateHandles(); + + QPolygonF m_lastPoints; //记录上一时刻的点集数据,用于缩放等操作 + QPolygonF m_points; +}; + +#endif diff --git a/include/util/creatingSelector.h b/include/util/creatingSelector.h index 573741c..ac1e84d 100644 --- a/include/util/creatingSelector.h +++ b/include/util/creatingSelector.h @@ -12,6 +12,12 @@ #include "baseSelector.h" #include "global.h" +enum CreatingMethod +{ + CM_drag, //多拽,默认的创建方式 + CM_click //单击点选,如多边形、线段等 +}; + class GraphicsBaseItem; class CreatingSelector : public BaseSelector { @@ -22,14 +28,15 @@ public: virtual ~CreatingSelector(); public: - void mousePressEvent(QGraphicsSceneMouseEvent*, DesignerScene*); - void mouseMoveEvent(QGraphicsSceneMouseEvent*, DesignerScene*); - void mouseReleaseEvent(QGraphicsSceneMouseEvent*, DesignerScene*); + virtual void mousePressEvent(QGraphicsSceneMouseEvent*, DesignerScene*); + virtual void mouseMoveEvent(QGraphicsSceneMouseEvent*, DesignerScene*); + virtual void mouseReleaseEvent(QGraphicsSceneMouseEvent*, DesignerScene*); - void setCreatingItem(GraphicsItemType& type) { m_creatingType=type; } + void setCreatingItem(GraphicsItemType& type) { m_creatingItemType=type; } private: - GraphicsItemType m_creatingType; + CreatingMethod m_creatingMethod; + GraphicsItemType m_creatingItemType; GraphicsBaseItem* m_pCreatingItem; QPointF m_scalBasePoint; }; diff --git a/source/graphicElementsPanel.cpp b/source/graphicElementsPanel.cpp index 843b9f2..2213ca5 100644 --- a/source/graphicElementsPanel.cpp +++ b/source/graphicElementsPanel.cpp @@ -11,6 +11,8 @@ GraphicElementsPanel::GraphicElementsPanel(QWidget *parent) connect(ui->pushBtn_rect, SIGNAL(clicked()), this, SLOT(onBtnClicked_GraphicsItem())); ui->pushBtn_roundRect->setProperty("shap",GIT_roundRect); connect(ui->pushBtn_roundRect, SIGNAL(clicked()), this, SLOT(onBtnClicked_GraphicsItem())); + ui->pushBtn_polygon->setProperty("shap",GIT_polygon); + connect(ui->pushBtn_polygon, SIGNAL(clicked()), this, SLOT(onBtnClicked_GraphicsItem())); } GraphicElementsPanel::~GraphicElementsPanel() diff --git a/source/graphicsItem/graphicsPolygonItem.cpp b/source/graphicsItem/graphicsPolygonItem.cpp new file mode 100644 index 0000000..25dcea4 --- /dev/null +++ b/source/graphicsItem/graphicsPolygonItem.cpp @@ -0,0 +1,136 @@ +#include "graphicsItem/graphicsPolygonItem.h" +#include "graphicsItem/itemControlHandle.h" + +#include + +GraphicPolygonItem::GraphicPolygonItem(QGraphicsItem *parent) + : GraphicsBaseItem(parent) +{ + m_pen = QPen(Qt::black); + m_brush = QBrush(Qt::NoBrush); +} + +GraphicPolygonItem::~GraphicPolygonItem() +{ + +} + +QPainterPath GraphicPolygonItem::shape() +{ + QPainterPath path; + path.addPolygon(m_points); + path.closeSubpath(); //将路径闭合 + return path; +} + +QRectF GraphicPolygonItem::boundingRect() +{ + //m_boundingRect = shape().controlPointRect(); //返回路径中所有点和控制点的矩形,文档介绍比返回精确边界框的boundingRect()函数计算要快 + return m_boundingRect; +} + +void GraphicPolygonItem::updateHandles() +{ + GraphicsBaseItem::updateHandles(); + for(int i = 0; i < m_points.size(); i++) + { + m_vecHanle[H_edit + i -1]->move(m_points[i].x(), m_points[i].y()); + } +} + +void GraphicPolygonItem::updateCoordinate() //当执行了resie和editShape函数后,boundingRect发生了变换,需要将item的原点(以中心点为原点)校准至boundingRect.center() +{ + QPointF pt1, pt2, delta; + pt1 = mapToScene(QPointF(0, 0)); + pt2 = mapToScene(m_boundingRect.center()); + delta = pt1 - pt2; + + if (!parentItem()) + { + prepareGeometryChange(); + //更改图形绘制节点坐标,让图形中心和原点对齐 + for(int i=0; isetPen(m_pen); + painter->setBrush(m_brush); + painter->drawPolygon(m_points); +} + +void GraphicPolygonItem::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_points = trans.map(m_lastPoints); + m_boundingRect = m_points.boundingRect(); + m_dWidth = m_boundingRect.width(); + m_dHeight = m_boundingRect.height(); + updateHandles(); +} + +void GraphicPolygonItem::move(const QPointF& point) +{ + moveBy(point.x(), point.y()); +} + +void GraphicPolygonItem::editShape(int nHandle,const QPointF& ptMouse) +{ + QPointF pt = mapFromScene(ptMouse); + m_points[nHandle - H_left - 1] = pt; + prepareGeometryChange(); + m_boundingRect = m_points.boundingRect(); + m_dWidth = m_boundingRect.width(); + m_dHeight = m_boundingRect.height(); + m_lastPoints = m_points; + updateHandles(); +} + +void GraphicPolygonItem::addPoint(const QPointF& point) +{ + m_points.append(mapFromScene(point)); + int nCount = m_points.count(); + //每个顶点都可以编辑,所以一个顶点需要编辑handle + ItemControlHandle* pHandle = new ItemControlHandle(this); + pHandle->setType(T_editShape); + pHandle->setTag(H_edit + nCount - 1); + m_vecHanle.push_back(pHandle); +} + +bool GraphicPolygonItem::endDrawing() +{ + bool bSuccess = true; + int nPointCount = m_points.count(); + if(nPointCount < 3) + bSuccess = false; + + return bSuccess; +} diff --git a/source/graphicsItem/graphicsRectItem.cpp b/source/graphicsItem/graphicsRectItem.cpp index 1eb3377..42b09e6 100644 --- a/source/graphicsItem/graphicsRectItem.cpp +++ b/source/graphicsItem/graphicsRectItem.cpp @@ -61,29 +61,29 @@ void GraphicsRectItem::updateHandles() m_vecHanle[H_edit -1]->move(boundingRect.right() - boundingRect.width() * m_dRatioX, boundingRect.top()); m_vecHanle[H_edit + 1 -1]->move(boundingRect.right(), boundingRect.top() + boundingRect.height() * m_dRatioY); } - } -void GraphicsRectItem::updateCoordinate() +void GraphicsRectItem::updateCoordinate() //当执行了resie和editShape函数后,boundingRect发生了变换,需要将item的原点(以中心点为原点)校准至boundingRect.center() { QPointF pt1, pt2, delta; - pt1 = mapToScene(transformOriginPoint()); + pt1 = mapToScene(QPointF(0, 0)); pt2 = mapToScene(m_boundingRect.center()); delta = pt1 - pt2; if (!parentItem()) { prepareGeometryChange(); - //创建时boundingRect原点不在中心,刷新boundingRect并将变换原点设为中心点 + //boundingRect发生变化后原点偏离中心,将原点设为中心点 m_boundingRect = QRectF(-m_dWidth / 2, -m_dHeight / 2, m_dWidth, m_dHeight); - setTransformOriginPoint(m_boundingRect.center()); - //原点坐标变化后跟根据新坐标调整位置 + //setTransformOriginPoint(m_boundingRect.center()); //变换中心默认为item的(0,0)点,所以不执行这句话也没有问题 + //更改原点后自身绘制会在新坐标系下进行,会有跳转,所以需要将item整体做对应的移动 moveBy(-delta.x(), -delta.y()); updateHandles(); } m_lastBoudingRect = m_boundingRect; } + void GraphicsRectItem::paint(QPainter* painter, const QStyleOptionGraphicsItem* option, QWidget* widget) { painter->setPen(m_pen); @@ -102,6 +102,11 @@ void GraphicsRectItem::paint(QPainter* painter, const QStyleOptionGraphicsItem* } else painter->drawRect(m_boundingRect); + + //绘制变换原点 + // QPointF originPoint = transformOriginPoint(); + // painter->setPen(Qt::red); + // painter->drawEllipse(originPoint, 5, 5); } void GraphicsRectItem::resize(int nHandle,double dSX, double dSY, const QPointF& basePoint) @@ -140,12 +145,13 @@ void GraphicsRectItem::move(const QPointF& point) void GraphicsRectItem::editShape(int nHandle,const QPointF& ptMouse) { + QPointF ptOnItem = mapFromParent(ptMouse); switch (nHandle) { //横轴X控制点 case H_edit: { - double dMouseX = ptMouse.x(); + double dMouseX = ptOnItem.x(); if(dMouseX < m_boundingRect.center().x()) dMouseX = m_boundingRect.center().x(); else if(dMouseX > m_boundingRect.right()) @@ -159,7 +165,7 @@ void GraphicsRectItem::editShape(int nHandle,const QPointF& ptMouse) //纵轴Y控制点 case H_edit + 1: { - double dMouseY = ptMouse.y(); + double dMouseY = ptOnItem.y(); if(dMouseY > m_boundingRect.center().y()) dMouseY = m_boundingRect.center().y(); else if(dMouseY < m_boundingRect.top()) diff --git a/source/util/creatingSelector.cpp b/source/util/creatingSelector.cpp index 70efabd..42ad089 100644 --- a/source/util/creatingSelector.cpp +++ b/source/util/creatingSelector.cpp @@ -1,5 +1,6 @@ #include "util/creatingSelector.h" #include "graphicsItem/graphicsRectItem.h" +#include "graphicsItem/graphicsPolygonItem.h" #include #include @@ -7,6 +8,7 @@ CreatingSelector::CreatingSelector(QObject *parent) : BaseSelector(parent) { m_type = ST_cerating; + m_creatingMethod = CM_drag; m_pCreatingItem = nullptr; m_scalBasePoint = QPointF(); } @@ -20,35 +22,68 @@ void CreatingSelector::mousePressEvent(QGraphicsSceneMouseEvent* event, Designer if (event->button() != Qt::LeftButton) return; - scene->clearSelection(); ms_ptMouseDown = event->scenePos(); ms_ptMouseLast = event->scenePos(); - switch (m_creatingType) { - case GIT_rect: - m_pCreatingItem = new GraphicsRectItem(QRect(1, 1, 1, 1)); + if(m_pCreatingItem == nullptr) + { + scene->clearSelection(); + + switch (m_creatingItemType) + { + case GIT_rect: + { + m_creatingMethod = CM_drag; + m_pCreatingItem = new GraphicsRectItem(QRect(1, 1, 1, 1)); + } break; - case GIT_roundRect: - m_pCreatingItem = new GraphicsRectItem(QRect(1, 1, 1, 1), true); + case GIT_roundRect: + { + m_creatingMethod = CM_drag; + m_pCreatingItem = new GraphicsRectItem(QRect(1, 1, 1, 1), true); + } break; - default: + case GIT_polygon: + { + m_creatingMethod = CM_click; + m_pCreatingItem = new GraphicPolygonItem(); + } break; + default: + break; + } + + if(m_pCreatingItem) + { + m_pCreatingItem->setPos(event->scenePos()); + m_pCreatingItem->setSelected(true); + scene->addItem(m_pCreatingItem); + + if(m_creatingMethod == CM_drag) + { + ms_ptMouseDown += QPoint(2, 2); + ms_nDragHandle = H_rightBottom; + } + else if(m_creatingMethod == CM_click) + m_pCreatingItem->addPoint(ms_ptMouseDown); + } } - ms_ptMouseDown += QPoint(2, 2); - m_pCreatingItem->setPos(event->scenePos()); - scene->addItem(m_pCreatingItem); - m_pCreatingItem->setSelected(true); + if(m_pCreatingItem && m_creatingMethod == CM_click) + { + //创建时添加了第一个点,紧接着再次添加第二点,然后从第二个点开始进行移动绘制 + m_pCreatingItem->addPoint(ms_ptMouseDown); + ms_nDragHandle = m_pCreatingItem->handleCount(); + } - ms_nDragHandle = H_rightBottom; - setCursor(scene, Qt::CrossCursor); } void CreatingSelector::mouseMoveEvent(QGraphicsSceneMouseEvent* event, DesignerScene* scene) { + setCursor(scene, Qt::CrossCursor); ms_ptMouseLast = event->scenePos(); - if (m_pCreatingItem) + if (m_pCreatingItem && m_creatingMethod == CM_drag) { if(m_scalBasePoint.isNull()) //基准点不能采用临时变量,因为handle的坐标也在不断变化,计算会出现问题 @@ -68,28 +103,51 @@ void CreatingSelector::mouseMoveEvent(QGraphicsSceneMouseEvent* event, DesignerS m_pCreatingItem->resize(ms_nDragHandle, sx, sy, m_scalBasePoint); } + else if (m_pCreatingItem && m_creatingMethod == CM_click) + { + if(ms_nDragHandle > H_left) + { + m_pCreatingItem->editShape(ms_nDragHandle, ms_ptMouseLast); + } + } } void CreatingSelector::mouseReleaseEvent(QGraphicsSceneMouseEvent* event, DesignerScene* scene) { - if (event->scenePos() == (ms_ptMouseDown - QPoint(2, 2))) //最小拖动范围 + if (m_pCreatingItem && m_creatingMethod == CM_drag) { - if(m_pCreatingItem) + if (event->scenePos() == (ms_ptMouseDown - QPoint(2, 2))) //最小拖动范围 { m_pCreatingItem->setSelected(false); scene->removeItem(m_pCreatingItem); delete m_pCreatingItem; } - } - else if (m_pCreatingItem && ms_ptMouseLast != ms_ptMouseDown) - { - m_pCreatingItem->updateCoordinate(); - emit scene->signalAddItem(m_pCreatingItem); - } + else if (ms_ptMouseLast != ms_ptMouseDown) + { + m_pCreatingItem->updateCoordinate(); + emit scene->signalAddItem(m_pCreatingItem); + } - ms_nDragHandle = H_none; - m_pCreatingItem = nullptr; - m_scalBasePoint = QPointF(); - setCursor(scene, Qt::ArrowCursor); - emit setWorkingSelector(ST_base); + ms_nDragHandle = H_none; + m_pCreatingItem = nullptr; + m_scalBasePoint = QPointF(); + setCursor(scene, Qt::ArrowCursor); + emit setWorkingSelector(ST_base); + } + else if (m_pCreatingItem && m_creatingMethod == CM_click && event->button() == Qt::RightButton) //右键结束绘制 + { + if(m_pCreatingItem->endDrawing()) + m_pCreatingItem->updateCoordinate(); + else + { + m_pCreatingItem->setSelected(false); + scene->removeItem(m_pCreatingItem); + delete m_pCreatingItem; + } + + ms_nDragHandle = H_none; + m_pCreatingItem = nullptr; + setCursor(scene, Qt::ArrowCursor); + emit setWorkingSelector(ST_base); + } } diff --git a/source/util/editingSelector.cpp b/source/util/editingSelector.cpp index d70b0ba..a42d9b6 100644 --- a/source/util/editingSelector.cpp +++ b/source/util/editingSelector.cpp @@ -1,4 +1,4 @@ -#include "util/EditingSelector.h" +#include "util/editingSelector.h" #include #include #include @@ -29,8 +29,7 @@ void EditingSelector::mouseMoveEvent(QGraphicsSceneMouseEvent* event, DesignerSc { if(ms_nDragHandle > H_left) { - QPointF ptOnItem = item->mapFromParent(ms_ptMouseLast); - item->editShape(ms_nDragHandle, ptOnItem); + item->editShape(ms_nDragHandle, ms_ptMouseLast); } } } diff --git a/source/util/movingSelector.cpp b/source/util/movingSelector.cpp index f6b8e2d..a54c388 100644 --- a/source/util/movingSelector.cpp +++ b/source/util/movingSelector.cpp @@ -1,4 +1,4 @@ -#include "util/MovingSelector.h" +#include "util/movingSelector.h" #include #include #include diff --git a/source/util/selectorManager.cpp b/source/util/selectorManager.cpp index 54d2dd6..fb629ed 100644 --- a/source/util/selectorManager.cpp +++ b/source/util/selectorManager.cpp @@ -2,7 +2,7 @@ #include "util/creatingSelector.h" #include "util/movingSelector.h" #include "util/scalingSelector.h" -#include "util/EditingSelector.h" +#include "util/editingSelector.h" SelectorManager* SelectorManager::m_pInstance = nullptr; diff --git a/ui/graphicElementsPanel.ui b/ui/graphicElementsPanel.ui index 911c96c..d18d984 100644 --- a/ui/graphicElementsPanel.ui +++ b/ui/graphicElementsPanel.ui @@ -52,6 +52,19 @@ 圆角矩形 + + + + 30 + 180 + 81 + 51 + + + + 多边形 + +