实现多边形的绘制及编辑

This commit is contained in:
duanshengchao 2024-08-20 19:42:42 +08:00
parent 7325dca259
commit b4040266dd
12 changed files with 308 additions and 48 deletions

View File

@ -51,6 +51,7 @@ set(H_HEADER_FILES
include/graphicsItem/itemControlHandle.h include/graphicsItem/itemControlHandle.h
include/graphicsItem/graphicsBaseItem.h include/graphicsItem/graphicsBaseItem.h
include/graphicsItem/graphicsRectItem.h include/graphicsItem/graphicsRectItem.h
include/graphicsItem/graphicsPolygonItem.h
) )
set(CPP_SOURCE_FILES set(CPP_SOURCE_FILES
source/main.cpp source/main.cpp
@ -71,6 +72,7 @@ set(CPP_SOURCE_FILES
source/graphicsItem/itemControlHandle.cpp source/graphicsItem/itemControlHandle.cpp
source/graphicsItem/graphicsBaseItem.cpp source/graphicsItem/graphicsBaseItem.cpp
source/graphicsItem/graphicsRectItem.cpp source/graphicsItem/graphicsRectItem.cpp
source/graphicsItem/graphicsPolygonItem.cpp
) )
set(UI_FILES set(UI_FILES
ui/mainwindow.ui ui/mainwindow.ui

View File

@ -72,9 +72,9 @@ public:
} }
//移动副本相关 //移动副本相关
virtual void createMovingCopy() {}; virtual void createMovingCopy() {}
virtual void removeMovingCopy() {}; virtual void removeMovingCopy() {}
virtual void moveMovingCopy(const QPointF&) {}; virtual void moveMovingCopy(const QPointF&) {}
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&) {}
@ -83,6 +83,7 @@ public:
virtual void updateCoordinate() {} virtual void updateCoordinate() {}
//handle相关 //handle相关
virtual int handleCount() { return m_vecHanle.count(); }
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++)
@ -198,6 +199,9 @@ public:
virtual void createMovingCopy(); virtual void createMovingCopy();
virtual void removeMovingCopy(); virtual void removeMovingCopy();
virtual void moveMovingCopy(const QPointF&); virtual void moveMovingCopy(const QPointF&);
//多边形、线段等点选创建的对象需要的函数
virtual void addPoint(const QPointF&) {}
virtual bool endDrawing() { return true; }
protected: protected:
virtual QVariant itemChange(QGraphicsItem::GraphicsItemChange, const QVariant&); virtual QVariant itemChange(QGraphicsItem::GraphicsItemChange, const QVariant&);

View File

@ -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

View File

@ -12,6 +12,12 @@
#include "baseSelector.h" #include "baseSelector.h"
#include "global.h" #include "global.h"
enum CreatingMethod
{
CM_drag, //多拽,默认的创建方式
CM_click //单击点选,如多边形、线段等
};
class GraphicsBaseItem; class GraphicsBaseItem;
class CreatingSelector : public BaseSelector class CreatingSelector : public BaseSelector
{ {
@ -22,14 +28,15 @@ public:
virtual ~CreatingSelector(); virtual ~CreatingSelector();
public: public:
void mousePressEvent(QGraphicsSceneMouseEvent*, DesignerScene*); virtual void mousePressEvent(QGraphicsSceneMouseEvent*, DesignerScene*);
void mouseMoveEvent(QGraphicsSceneMouseEvent*, DesignerScene*); virtual void mouseMoveEvent(QGraphicsSceneMouseEvent*, DesignerScene*);
void mouseReleaseEvent(QGraphicsSceneMouseEvent*, DesignerScene*); virtual void mouseReleaseEvent(QGraphicsSceneMouseEvent*, DesignerScene*);
void setCreatingItem(GraphicsItemType& type) { m_creatingType=type; } void setCreatingItem(GraphicsItemType& type) { m_creatingItemType=type; }
private: private:
GraphicsItemType m_creatingType; CreatingMethod m_creatingMethod;
GraphicsItemType m_creatingItemType;
GraphicsBaseItem* m_pCreatingItem; GraphicsBaseItem* m_pCreatingItem;
QPointF m_scalBasePoint; QPointF m_scalBasePoint;
}; };

View File

@ -11,6 +11,8 @@ GraphicElementsPanel::GraphicElementsPanel(QWidget *parent)
connect(ui->pushBtn_rect, SIGNAL(clicked()), this, SLOT(onBtnClicked_GraphicsItem())); connect(ui->pushBtn_rect, SIGNAL(clicked()), this, SLOT(onBtnClicked_GraphicsItem()));
ui->pushBtn_roundRect->setProperty("shap",GIT_roundRect); ui->pushBtn_roundRect->setProperty("shap",GIT_roundRect);
connect(ui->pushBtn_roundRect, SIGNAL(clicked()), this, SLOT(onBtnClicked_GraphicsItem())); 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() GraphicElementsPanel::~GraphicElementsPanel()

View File

@ -0,0 +1,136 @@
#include "graphicsItem/graphicsPolygonItem.h"
#include "graphicsItem/itemControlHandle.h"
#include <QPainter>
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; i<m_points.count(); i++)
m_points[i] += delta;
m_boundingRect = m_points.boundingRect();
//移动整体图形,消除节点坐标更后的绘制跳转
moveBy(-delta.x(), -delta.y());
updateHandles();
}
m_lastPoints = m_points;
}
void GraphicPolygonItem::paint(QPainter* painter, const QStyleOptionGraphicsItem* option, QWidget* widget)
{
painter->setPen(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;
}

View File

@ -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]->move(boundingRect.right() - boundingRect.width() * m_dRatioX, boundingRect.top());
m_vecHanle[H_edit + 1 -1]->move(boundingRect.right(), boundingRect.top() + boundingRect.height() * m_dRatioY); 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; QPointF pt1, pt2, delta;
pt1 = mapToScene(transformOriginPoint()); pt1 = mapToScene(QPointF(0, 0));
pt2 = mapToScene(m_boundingRect.center()); pt2 = mapToScene(m_boundingRect.center());
delta = pt1 - pt2; delta = pt1 - pt2;
if (!parentItem()) if (!parentItem())
{ {
prepareGeometryChange(); prepareGeometryChange();
//创建时boundingRect原点不在中心刷新boundingRect并将变换原点设为中心点 //boundingRect发生变化后原点偏离中心原点设为中心点
m_boundingRect = QRectF(-m_dWidth / 2, -m_dHeight / 2, m_dWidth, m_dHeight); 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()); moveBy(-delta.x(), -delta.y());
updateHandles(); updateHandles();
} }
m_lastBoudingRect = m_boundingRect; m_lastBoudingRect = m_boundingRect;
} }
void GraphicsRectItem::paint(QPainter* painter, const QStyleOptionGraphicsItem* option, QWidget* widget) void GraphicsRectItem::paint(QPainter* painter, const QStyleOptionGraphicsItem* option, QWidget* widget)
{ {
painter->setPen(m_pen); painter->setPen(m_pen);
@ -102,6 +102,11 @@ void GraphicsRectItem::paint(QPainter* painter, const QStyleOptionGraphicsItem*
} }
else else
painter->drawRect(m_boundingRect); 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) 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) void GraphicsRectItem::editShape(int nHandle,const QPointF& ptMouse)
{ {
QPointF ptOnItem = mapFromParent(ptMouse);
switch (nHandle) switch (nHandle)
{ {
//横轴X控制点 //横轴X控制点
case H_edit: case H_edit:
{ {
double dMouseX = ptMouse.x(); double dMouseX = ptOnItem.x();
if(dMouseX < m_boundingRect.center().x()) if(dMouseX < m_boundingRect.center().x())
dMouseX = m_boundingRect.center().x(); dMouseX = m_boundingRect.center().x();
else if(dMouseX > m_boundingRect.right()) else if(dMouseX > m_boundingRect.right())
@ -159,7 +165,7 @@ void GraphicsRectItem::editShape(int nHandle,const QPointF& ptMouse)
//纵轴Y控制点 //纵轴Y控制点
case H_edit + 1: case H_edit + 1:
{ {
double dMouseY = ptMouse.y(); double dMouseY = ptOnItem.y();
if(dMouseY > m_boundingRect.center().y()) if(dMouseY > m_boundingRect.center().y())
dMouseY = m_boundingRect.center().y(); dMouseY = m_boundingRect.center().y();
else if(dMouseY < m_boundingRect.top()) else if(dMouseY < m_boundingRect.top())

View File

@ -1,5 +1,6 @@
#include "util/creatingSelector.h" #include "util/creatingSelector.h"
#include "graphicsItem/graphicsRectItem.h" #include "graphicsItem/graphicsRectItem.h"
#include "graphicsItem/graphicsPolygonItem.h"
#include <QGraphicsSceneMouseEvent> #include <QGraphicsSceneMouseEvent>
#include <QGraphicsView> #include <QGraphicsView>
@ -7,6 +8,7 @@ CreatingSelector::CreatingSelector(QObject *parent)
: BaseSelector(parent) : BaseSelector(parent)
{ {
m_type = ST_cerating; m_type = ST_cerating;
m_creatingMethod = CM_drag;
m_pCreatingItem = nullptr; m_pCreatingItem = nullptr;
m_scalBasePoint = QPointF(); m_scalBasePoint = QPointF();
} }
@ -20,35 +22,68 @@ void CreatingSelector::mousePressEvent(QGraphicsSceneMouseEvent* event, Designer
if (event->button() != Qt::LeftButton) if (event->button() != Qt::LeftButton)
return; return;
scene->clearSelection();
ms_ptMouseDown = event->scenePos(); ms_ptMouseDown = event->scenePos();
ms_ptMouseLast = event->scenePos(); ms_ptMouseLast = event->scenePos();
switch (m_creatingType) { if(m_pCreatingItem == nullptr)
case GIT_rect: {
m_pCreatingItem = new GraphicsRectItem(QRect(1, 1, 1, 1)); scene->clearSelection();
switch (m_creatingItemType)
{
case GIT_rect:
{
m_creatingMethod = CM_drag;
m_pCreatingItem = new GraphicsRectItem(QRect(1, 1, 1, 1));
}
break; break;
case GIT_roundRect: case GIT_roundRect:
m_pCreatingItem = new GraphicsRectItem(QRect(1, 1, 1, 1), true); {
m_creatingMethod = CM_drag;
m_pCreatingItem = new GraphicsRectItem(QRect(1, 1, 1, 1), true);
}
break; break;
default: case GIT_polygon:
{
m_creatingMethod = CM_click;
m_pCreatingItem = new GraphicPolygonItem();
}
break; 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); if(m_pCreatingItem && m_creatingMethod == CM_click)
m_pCreatingItem->setPos(event->scenePos()); {
scene->addItem(m_pCreatingItem); //创建时添加了第一个点,紧接着再次添加第二点,然后从第二个点开始进行移动绘制
m_pCreatingItem->setSelected(true); 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) void CreatingSelector::mouseMoveEvent(QGraphicsSceneMouseEvent* event, DesignerScene* scene)
{ {
setCursor(scene, Qt::CrossCursor);
ms_ptMouseLast = event->scenePos(); ms_ptMouseLast = event->scenePos();
if (m_pCreatingItem) if (m_pCreatingItem && m_creatingMethod == CM_drag)
{ {
if(m_scalBasePoint.isNull()) //基准点不能采用临时变量因为handle的坐标也在不断变化计算会出现问题 if(m_scalBasePoint.isNull()) //基准点不能采用临时变量因为handle的坐标也在不断变化计算会出现问题
@ -68,28 +103,51 @@ void CreatingSelector::mouseMoveEvent(QGraphicsSceneMouseEvent* event, DesignerS
m_pCreatingItem->resize(ms_nDragHandle, sx, sy, m_scalBasePoint); 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) 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); m_pCreatingItem->setSelected(false);
scene->removeItem(m_pCreatingItem); scene->removeItem(m_pCreatingItem);
delete m_pCreatingItem; delete m_pCreatingItem;
} }
} else if (ms_ptMouseLast != ms_ptMouseDown)
else if (m_pCreatingItem && ms_ptMouseLast != ms_ptMouseDown) {
{ m_pCreatingItem->updateCoordinate();
m_pCreatingItem->updateCoordinate(); emit scene->signalAddItem(m_pCreatingItem);
emit scene->signalAddItem(m_pCreatingItem); }
}
ms_nDragHandle = H_none; ms_nDragHandle = H_none;
m_pCreatingItem = nullptr; m_pCreatingItem = nullptr;
m_scalBasePoint = QPointF(); m_scalBasePoint = QPointF();
setCursor(scene, Qt::ArrowCursor); setCursor(scene, Qt::ArrowCursor);
emit setWorkingSelector(ST_base); 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);
}
} }

View File

@ -1,4 +1,4 @@
#include "util/EditingSelector.h" #include "util/editingSelector.h"
#include <QGraphicsSceneMouseEvent> #include <QGraphicsSceneMouseEvent>
#include <QGraphicsView> #include <QGraphicsView>
#include <graphicsItem/graphicsBaseItem.h> #include <graphicsItem/graphicsBaseItem.h>
@ -29,8 +29,7 @@ void EditingSelector::mouseMoveEvent(QGraphicsSceneMouseEvent* event, DesignerSc
{ {
if(ms_nDragHandle > H_left) if(ms_nDragHandle > H_left)
{ {
QPointF ptOnItem = item->mapFromParent(ms_ptMouseLast); item->editShape(ms_nDragHandle, ms_ptMouseLast);
item->editShape(ms_nDragHandle, ptOnItem);
} }
} }
} }

View File

@ -1,4 +1,4 @@
#include "util/MovingSelector.h" #include "util/movingSelector.h"
#include <QGraphicsSceneMouseEvent> #include <QGraphicsSceneMouseEvent>
#include <QGraphicsView> #include <QGraphicsView>
#include <graphicsItem/graphicsBaseItem.h> #include <graphicsItem/graphicsBaseItem.h>

View File

@ -2,7 +2,7 @@
#include "util/creatingSelector.h" #include "util/creatingSelector.h"
#include "util/movingSelector.h" #include "util/movingSelector.h"
#include "util/scalingSelector.h" #include "util/scalingSelector.h"
#include "util/EditingSelector.h" #include "util/editingSelector.h"
SelectorManager* SelectorManager::m_pInstance = nullptr; SelectorManager* SelectorManager::m_pInstance = nullptr;

View File

@ -52,6 +52,19 @@
<string>圆角矩形</string> <string>圆角矩形</string>
</property> </property>
</widget> </widget>
<widget class="QPushButton" name="pushBtn_polygon">
<property name="geometry">
<rect>
<x>30</x>
<y>180</y>
<width>81</width>
<height>51</height>
</rect>
</property>
<property name="text">
<string>多边形</string>
</property>
</widget>
</widget> </widget>
<widget class="QWidget" name="tab_2"> <widget class="QWidget" name="tab_2">
<attribute name="title"> <attribute name="title">