先看一个简单的例子
#include "mainwindow.h"
#include "ui_mainwindow.h"
#include
#include
MainWindow::MainWindow(QWidget *parent) :
QMainWindow(parent),
ui(new Ui::MainWindow)
{
ui->setupUi(this);
init();
}
MainWindow::~MainWindow()
{
delete ui;
}
void MainWindow::init()
{
QGraphicsScene *pScene = new QGraphicsScene();
pScene->addText("Hello, world!");
QGraphicsView *pView = new QGraphicsView(pScene, this);
}
在界面上(LabelGraphicsView类)需要有一个成员变量(m_graphicsBaseItem )负责当前图元的绘画。这个成员变量可以画多种类型的图元。
设计一个基类 GraphicsBaseItem (继承自QGraphicsItem),再扩展两个子类:
需要画矩形时,就把MyRectangleItem 赋值到GraphicsBaseItem ,调用paint函数绘制。需要画多边形时,使用MyRectangleItem
每个图元类自己内部维护一个画图状态(m_drawFinished)。如画图未完成,则可以继续加点,可以更新实时动态等。
成员变量(m_graphicsBaseItem )负责当前图元的绘画,画图完成之后,更新画图状态(m_drawFinished),并重新new一个相同的图元,添加当场景中。清空成员变量(m_graphicsBaseItem )的值,等待下一个图元的绘制
至少需要考虑一下场景:
#ifndef GRAPHICSBASEITEM_H
#define GRAPHICSBASEITEM_H
#include
#include "globaldefine.h"
class GraphicsBaseItem : public QGraphicsItem
{
public:
GraphicsBaseItem(const QPolygonF& pts,
bool drawFinished = false,
QGraphicsItem *parent = Q_NULLPTR);
// 查看图形类型,比如矩形,多边形
virtual ShapeType GetShapeType() = 0;
// 查看是否包含这个点
virtual bool Contains(const QPointF& pt) = 0;
//是否完成了绘图(鼠标拖动场景下使用,或者多边形绘制)
virtual void FinishDrawing();
//添加点,获取点
void AddPoint(const QPointF& point);
int GetPointCounts();
bool GetPoint(int id, QPointF& pt);
QPolygonF GetPoints();
bool RemoveLastPoint();
int GetNearestVertex(const QPointF& pt);
//设置当前鼠标位置
void SetMousePt(const QPointF& mousePt);
//重置
void Reset();
//是否被选中
void SetSelected(bool isSelected);
virtual QRectF boundingRect() const override;
protected:
QPolygonF m_pts;//闭合曲线首尾点无需重复存储
QPointF m_mousePt;//画图时鼠标当前位置点
bool m_selected;//是否被选中
bool m_drawFinished;//是否完成绘图
};
#endif // GRAPHICSBASEITEM_H
主要实现该类的绘图功能 paint
#ifndef MYRECTANGLEITEM_H
#define MYRECTANGLEITEM_H
#include "globaldefine.h"
#include"mygraphicsbaseitem.h"
class MyRectangleItem : public GraphicsBaseItem
{
public:
MyRectangleItem(const QPolygonF& pts,bool drawFinished = false,GraphicsBaseItem *parent = Q_NULLPTR);
virtual ShapeType GetShapeType();
//绘图 在updata后调用 MyPolylineItem
virtual void paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget) override;
virtual bool Contains(const QPointF& pt);
virtual void FinishDrawing();//完成绘制并检查点的位置是否是左上点和右下点,如果不是就更新
};
#endif // MYRECTANGLEITEM_H
具体实现
#include "myrectangleitem.h"
#include
#include
namespace
{
bool IsGreaterThan(double d1, double d2)//比较d1是否大于d2
{
double eps = 1.0e-6;
double delta = d1 - d2;
if (delta > eps)
{
return true;
}
else
{
return false;
}
}
QRectF makeRect(const QPointF& pt1, const QPointF& pt2)
{
double topLeftX = IsGreaterThan(pt1.x(), pt2.x()) ? pt2.x() : pt1.x();
double topLeftY = IsGreaterThan(pt1.y(), pt2.y()) ? pt2.y() : pt1.y();
double width = qAbs(pt1.x() - pt2.x());
double height = qAbs(pt1.y() - pt2.y());
return QRectF(topLeftX, topLeftY, width, height);
}
}
MyRectangleItem::MyRectangleItem(const QPolygonF& pts,bool drawFinished ,GraphicsBaseItem *parent )
:GraphicsBaseItem(pts, drawFinished, parent)
{
}
ShapeType MyRectangleItem::GetShapeType()
{
return RECTANGLE;
}
void MyRectangleItem::paint(QPainter * painter, const QStyleOptionGraphicsItem * option, QWidget * widget)
{
if (m_pts.isEmpty())
{
return;
}
painter->setPen(Qt::blue);
painter->setBrush(Qt::NoBrush);
painter->setOpacity(1.0);
if (m_drawFinished)
{
if (m_pts.size() == 2)
{
QRectF rect = makeRect(m_pts[0], m_pts[1]);
painter->drawRect(rect);
painter->setBrush(Qt::blue);
qDebug() <<"finish "<< m_pts[0] <<" , "<< m_pts[1];
}
}
else
{
QRectF rect = makeRect(m_pts[0], m_mousePt);//m_mousePt用于追踪鼠标绘制
painter->drawRect(rect);
qDebug() << "unfinish " << m_pts[0] << " , " << m_mousePt;
}
}
bool MyRectangleItem::Contains(const QPointF & pt)
{
if (m_pts.count() != 2)
{
return false;
}
QRectF rect(m_pts[0],m_pts[1]);
bool ret = rect.contains(pt);
return ret;
}
void MyRectangleItem::FinishDrawing()
{
GraphicsBaseItem::FinishDrawing();
if (m_pts.count() == 2)
{
QRectF rect = makeRect(m_pts[0], m_pts[1]);
QPointF topLeft = rect.topLeft();
QPointF bottomRight = rect.bottomRight();
if (topLeft != m_pts[0] || bottomRight != m_pts[1])
{
QPolygonF pts;
pts.push_back(topLeft);
pts.push_back(bottomRight);
m_pts.swap(pts);
}
}
}
多边形类
MyPolylineItem
多边形由一系列点组成,起始点和终止点比较重要
需要设置终止方案。
#ifndef MYPOLYLINEITEM_H
#define MYPOLYLINEITEM_H
#include"mygraphicsbaseitem.h"
class MyPolylineItem : public GraphicsBaseItem
{
public:
MyPolylineItem(const QPolygonF& pts,bool drawFinished = false,GraphicsBaseItem *parent = Q_NULLPTR);
virtual ShapeType GetShapeType();
virtual void paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget) override;
virtual QPainterPath shape() const override;
virtual bool Contains(const QPointF& pt);
};
#endif // MYPOLYLINEITEM_H
纵向是三个鼠标事件
virtual void mousePressEvent(QMouseEvent *event) override; virtual
void mouseReleaseEvent(QMouseEvent *event) override; virtual void
mouseMoveEvent(QMouseEvent *event) override;
横向是两种图元
按下鼠标左键,不放开拖动到目标位置,放开。于是按照时间顺序依次触发
mousePressEvent 添加第一个点
mouseMoveEvent 界面实时更新鼠标位置 画矩形
mouseReleaseEvent 如果释放的点不是第一个点的位置,则认为是一个完整的矩形,添加最后一个点完成绘制。否则清空所有点
问题:
所以在界面类中,我们需要标记状态
#include "LabelGraphicsView.h"
#include "myrectangleitem.h"
#include
LabelGraphicsView::LabelGraphicsView()
{
init();
QVector<QPointF> pts;
m_GraphicsBaseItem = new MyRectangleItem(pts, false);
}
LabelGraphicsView::~LabelGraphicsView()
{
}
void LabelGraphicsView::init()
{
setBackgroundBrush(QColor(255, 255, 255));
setScene(&m_graphicsScene);
setRenderHints(QPainter::Antialiasing | QPainter::SmoothPixmapTransform);
setOptimizationFlags(QGraphicsView::DontSavePainterState);
setViewportUpdateMode(QGraphicsView::SmartViewportUpdate);
setTransformationAnchor(QGraphicsView::AnchorUnderMouse);
m_graphicsScene.setBackgroundBrush(Qt::darkGray);
}
void LabelGraphicsView::mousePressEvent(QMouseEvent *event)
{
//TODO:鼠标左键,点击绘制图形;
if (event->button() == Qt::LeftButton)
{
QPoint pos = event->pos();
QPointF leftButtonPressedPos = mapToScene(pos);
m_GraphicsBaseItem->AddPoint(leftButtonPressedPos);
viewport()->update();
}
QGraphicsView::mousePressEvent(event);
}
void LabelGraphicsView::mouseReleaseEvent(QMouseEvent *event)
{
//TODO:鼠标释放之后操作
QPoint pos = event->pos();
QPointF ReleasePos = mapToScene(pos);
m_GraphicsBaseItem->AddPoint(ReleasePos);
m_GraphicsBaseItem->FinishDrawing();
viewport()->update();
ShapeType shapeType = m_GraphicsBaseItem->GetShapeType();
QPolygonF pts = m_GraphicsBaseItem->GetPoints();
auto newItem = new MyRectangleItem(pts, true);
m_graphicsScene.addItem(newItem);
m_GraphicsBaseItem->Reset();
}
//实时获取鼠标最新位置并绘图
void LabelGraphicsView::mouseMoveEvent(QMouseEvent *event)
{
//TODO:鼠标移动时,如果存在有效图形类型,进行图形绘制
if (m_GraphicsBaseItem->GetShapeType() == RECTANGLE)
{
QPoint pos = event->pos();
QPointF movePos = mapToScene(pos);
m_GraphicsBaseItem->SetMousePt(movePos);
viewport()->update();
}
QGraphicsView::mouseMoveEvent(event);
}
未完待续
Qt中QGraphicsView架构下实时鼠标绘制图形
main.cpp
#include "LabelImg.h"
#include
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
LabelImg w;
w.show();
return a.exec();
}
ui 界面
LabelImg.h
#pragma once
#include "LabelGraphicsView.h"
#include
#include "ui_LabelImg.h"
class LabelImg : public QMainWindow
{
Q_OBJECT
public:
LabelImg(QWidget *parent = Q_NULLPTR);
private:
void init();
public slots:
void SlotRectangleButtonClicked();
void SlotPolylineButtonClicked();
private:
Ui::LabelImgClass ui;
LabelGraphicsView * m_graphicsView =nullptr;
};
#include "LabelImg.h"
#include
LabelImg::LabelImg(QWidget *parent)
: QMainWindow(parent)
{
ui.setupUi(this);
init();
connect(ui.rectangleButton, SIGNAL(clicked()),this, SLOT(SlotRectangleButtonClicked()));
connect(ui.polylineButton, SIGNAL(clicked()), this, SLOT(SlotPolylineButtonClicked()));
}
void LabelImg::init()
{
QVBoxLayout *vBoxLayout = new QVBoxLayout;
ui.widget->setLayout(vBoxLayout);
vBoxLayout->setMargin(2);
vBoxLayout->setSpacing(2);
m_graphicsView = new LabelGraphicsView( );
m_graphicsView->setFrameShape(QFrame::NoFrame);
m_graphicsView->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding);
m_graphicsView->setDragMode(QGraphicsView::RubberBandDrag);
m_graphicsView->setTransformationAnchor(QGraphicsView::AnchorUnderMouse);
vBoxLayout->addWidget(m_graphicsView);
}
void LabelImg::SlotRectangleButtonClicked()
{
m_graphicsView->setDrawRectangleModule();
}
void LabelImg::SlotPolylineButtonClicked()
{
m_graphicsView->setDrawPolylineModule();
}
LabelGraphicsView.h
#pragma once
#include
#include "mygraphicsbaseitem.h"
#include "myrectangleitem.h"
#include "mypolylineitem.h"
enum ProcessMode
{
DEFAULT = 0, // 默认模式
DRAW, //绘图模式
MOVE //移动模式
};
class LabelGraphicsView :
public QGraphicsView
{
public:
LabelGraphicsView();
~LabelGraphicsView();
void setDrawRectangleModule();
void setDrawPolylineModule();
virtual void mousePressEvent(QMouseEvent *event) override;
virtual void mouseReleaseEvent(QMouseEvent *event) override;
virtual void mouseMoveEvent(QMouseEvent *event) override;
private:
void init();
bool isSamePoint(QPointF p1, QPointF p2);
private:
QGraphicsScene m_graphicsScene;
GraphicsBaseItem* m_GraphicsBaseItem = nullptr;
MyRectangleItem *m_RectangleItem = nullptr;
MyPolylineItem * m_PolylineItem = nullptr;
ProcessMode m_processMode= DEFAULT;
};
#include "LabelGraphicsView.h"
#include
LabelGraphicsView::LabelGraphicsView()
{
init();
}
LabelGraphicsView::~LabelGraphicsView()
{
}
void LabelGraphicsView::init()
{
setBackgroundBrush(QColor(255, 255, 255));
setScene(&m_graphicsScene);
setRenderHints(QPainter::Antialiasing | QPainter::SmoothPixmapTransform);
setOptimizationFlags(QGraphicsView::DontSavePainterState);
setViewportUpdateMode(QGraphicsView::SmartViewportUpdate);
setTransformationAnchor(QGraphicsView::AnchorUnderMouse);
m_graphicsScene.setBackgroundBrush(Qt::darkGray);
setSceneRect(-300, -300, 600, 600);
QVector<QPointF> pts;
m_PolylineItem = new MyPolylineItem(pts, false);
QVector<QPointF> rpts;
m_RectangleItem = new MyRectangleItem(rpts, false);
m_graphicsScene.addItem(m_GraphicsBaseItem);
}
void LabelGraphicsView::setDrawRectangleModule()
{
if (m_GraphicsBaseItem)
{
m_GraphicsBaseItem->Reset();
m_GraphicsBaseItem = nullptr;
}
if (!m_RectangleItem)
{
QVector<QPointF> rpts;
m_RectangleItem = new MyRectangleItem(rpts, false);
}
m_GraphicsBaseItem =m_RectangleItem;
m_graphicsScene.addItem(m_GraphicsBaseItem);
}
void LabelGraphicsView::setDrawPolylineModule()
{
if (m_GraphicsBaseItem)
{
m_GraphicsBaseItem->Reset();
m_GraphicsBaseItem = nullptr;
}
if (!m_PolylineItem)
{
QVector<QPointF> pts;
m_PolylineItem = new MyPolylineItem(pts, false);
}
m_GraphicsBaseItem = m_PolylineItem;
m_graphicsScene.addItem(m_GraphicsBaseItem);
}
void LabelGraphicsView::mousePressEvent(QMouseEvent *event)
{
//TODO:鼠标左键,点击绘制图形;
if (event->button() == Qt::LeftButton && m_GraphicsBaseItem)
{
QPoint pos = event->pos();
QPointF leftButtonPressedPos = mapToScene(pos);
ShapeType shapeType = m_GraphicsBaseItem->GetShapeType();
switch (m_processMode)
{
case DEFAULT:
{
// 如果时默认模式,现在点击了鼠标,则进入绘图模式
m_processMode = DRAW;
if (shapeType == RECTANGLE)
{
m_GraphicsBaseItem->AddPoint(leftButtonPressedPos);
//m_graphicsScene.addItem((MyRectangleItem*)m_GraphicsBaseItem);
}
//POLYGON在mouseReleaseEvent加点
}
break;
case DRAW:
{
}
break;
case MOVE:
{
}
break;
}
viewport()->update();
}
//QGraphicsView::mousePressEvent(event);
}
void LabelGraphicsView::mouseReleaseEvent(QMouseEvent *event)
{
//TODO:鼠标释放之后操作
QPoint pos = event->pos();
QPointF ReleasePos = mapToScene(pos);
if (m_GraphicsBaseItem)
{
ShapeType shapeType = m_GraphicsBaseItem->GetShapeType();
switch (m_processMode)
{
case DRAW:
{
if (shapeType == RECTANGLE)
{
//结束矩形的绘制
m_GraphicsBaseItem->AddPoint(ReleasePos);
m_GraphicsBaseItem->FinishDrawing();
m_processMode = DEFAULT;
//将矩形加到场景中保存,将绘图的指针reset
QPolygonF pts = m_GraphicsBaseItem->GetPoints();
MyRectangleItem* newItem = new MyRectangleItem(pts, true);
m_graphicsScene.addItem(newItem);
//m_graphicsScene.removeItem(m_GraphicsBaseItem);
m_GraphicsBaseItem->Reset();
}
else if (shapeType == POLYGON)
{
QPointF firstPt;
if (!m_GraphicsBaseItem->GetPoint(0, firstPt))
{
m_GraphicsBaseItem->AddPoint(ReleasePos);
}
if (m_GraphicsBaseItem->GetPointCounts() > 1 && isSamePoint(firstPt, ReleasePos))
{
//结束多边形的绘制
m_GraphicsBaseItem->FinishDrawing();
m_processMode = DEFAULT;
//将矩形加到场景中保存,将绘图的指针reset
QPolygonF pts = m_GraphicsBaseItem->GetPoints();
auto newItem = new MyPolylineItem(pts, true);
m_graphicsScene.addItem(newItem);
//m_graphicsScene.removeItem(m_GraphicsBaseItem);
m_GraphicsBaseItem->Reset();
}
else
{
m_GraphicsBaseItem->AddPoint(ReleasePos);
}
}
}
break;
case MOVE:
{
}
break;
}
viewport()->update();
}
QGraphicsView::mouseReleaseEvent(event);//不写这行图元会错位
}
//实时获取鼠标最新位置并绘图
void LabelGraphicsView::mouseMoveEvent(QMouseEvent *event)
{
//TODO:鼠标移动时,如果存在有效图形类型,进行图形绘制
switch (m_processMode)
{
case DRAW:
{
QPoint pos = event->pos();
QPointF movePos = mapToScene(pos);
m_GraphicsBaseItem->SetMousePt(movePos);
}
break;
case MOVE:
{
}
break;
}
viewport()->update();
QGraphicsView::mouseMoveEvent(event);
}
bool LabelGraphicsView::isSamePoint(QPointF p1, QPointF p2)
{
QPointF dif = p1 - p2;
float distance = dif.manhattanLength();
//方圆5个像素点内
if (distance <= 5)
{
return true;
}
else
{
return false;
}
}
图元
mygraphicsbaseitem.h
#ifndef GRAPHICSBASEITEM_H
#define GRAPHICSBASEITEM_H
#include
#include "globaldefine.h"
class GraphicsBaseItem : public QGraphicsItem
{
public:
GraphicsBaseItem(const QPolygonF& pts,
bool drawFinished = false,
QGraphicsItem *parent = Q_NULLPTR);
~GraphicsBaseItem();
// 查看图形类型,比如矩形,多边形
virtual ShapeType GetShapeType() = 0;
// 查看是否包含这个点
virtual bool Contains(const QPointF& pt) = 0;
//是否完成了绘图(鼠标拖动场景下使用,或者多边形绘制)
virtual void FinishDrawing();
virtual void paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget) =0;
//添加点,获取点
void AddPoint(const QPointF& point);
int GetPointCounts();
bool GetPoint(int id, QPointF& pt);
QPolygonF GetPoints();
bool RemoveLastPoint();
int GetNearestVertex(const QPointF& pt);
//设置当前鼠标位置
void SetMousePt(const QPointF& mousePt);
//重置
void Reset();
//是否被选中
void SetSelected(bool isSelected);
virtual QRectF boundingRect() const override;
protected:
QPolygonF m_pts;//闭合曲线首尾点无需重复存储
QPointF m_mousePt;//画图时鼠标当前位置点
bool m_selected;//是否被选中
bool m_drawFinished;//是否完成绘图
};
#endif // GRAPHICSBASEITEM_H
#include "mygraphicsbaseitem.h"
#include
GraphicsBaseItem::GraphicsBaseItem(
const QPolygonF& pts,
bool drawFinished/* = false*/,
QGraphicsItem *parent/* = Q_NULLPTR*/)
: QGraphicsItem(parent), m_pts(pts), m_drawFinished(drawFinished)
{
if (m_pts.count() > 0)
{
m_mousePt = m_pts[0];
}
}
GraphicsBaseItem::~GraphicsBaseItem()
{
}
void GraphicsBaseItem::FinishDrawing()
{
m_drawFinished = true;
}
void GraphicsBaseItem::AddPoint(const QPointF & point)
{
if (m_drawFinished)
{
return;
}
if (m_pts.count() > 0)
{
bool hasPt = m_pts.contains(point);
if (hasPt)
{
return;
}
}
m_pts.push_back(point);
}
int GraphicsBaseItem::GetPointCounts()
{
return m_pts.count();
}
bool GraphicsBaseItem::GetPoint(int id, QPointF& pt)
{
if (id >= 0 && id < m_pts.size())
{
pt = m_pts[id];
return true;
}
return false;
}
QPolygonF GraphicsBaseItem::GetPoints()
{
return m_pts;
}
bool GraphicsBaseItem::RemoveLastPoint()
{
if (!m_pts.isEmpty())
{
m_pts.removeLast();
return true;
}
return false;
}
int GraphicsBaseItem::GetNearestVertex(const QPointF & pt)
{
int id = -1;
double minDistance = 999999.99;
double eps = 2.0;
for (int ii = 0; ii < m_pts.size(); ++ii)
{
QPointF ptII = m_pts[ii];
QPointF p = ptII - pt;
double dis = std::sqrt(p.x()*p.x() + p.y()*p.y());
if (dis < eps && dis < minDistance)
{
minDistance = dis;
id = ii;
}
}
return id;
}
void GraphicsBaseItem::SetMousePt(const QPointF & mousePt)
{
m_mousePt = mousePt;
}
void GraphicsBaseItem::Reset()
{
m_pts.clear();
m_drawFinished = false;
}
void GraphicsBaseItem::SetSelected(bool isSelected)
{
m_selected = isSelected;
}
QRectF GraphicsBaseItem::boundingRect() const
{
if (m_pts.size() > 1)
{
QPointF leftTop = m_pts[0];
QPointF rightBottom = m_pts[0];
for (int ii = 1; ii < m_pts.size(); ++ii)
{
QPointF pt = m_pts[ii];
if (pt.x() < leftTop.x())
{
leftTop.setX(pt.x());
}
if (pt.y() < leftTop.y())
{
leftTop.setY(pt.y());
}
if (pt.x() > rightBottom.x())
{
rightBottom.setX(pt.x());
}
if (pt.y() > rightBottom.y())
{
rightBottom.setY(pt.y());
}
}
return QRectF(leftTop, rightBottom);
}
//这行不写,m_graphicsScene.addItem(newItem)时,m_pts为空会直接崩掉
return QRectF();
}
矩形
myrectangleitem.h
#ifndef MYRECTANGLEITEM_H
#define MYRECTANGLEITEM_H
#include "globaldefine.h"
#include"mygraphicsbaseitem.h"
class MyRectangleItem : public GraphicsBaseItem
{
public:
MyRectangleItem(const QPolygonF& pts,bool drawFinished = false,GraphicsBaseItem *parent = Q_NULLPTR);
virtual ShapeType GetShapeType();
//绘图 在updata后调用 paint
virtual void paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget) override;
virtual bool Contains(const QPointF& pt);
virtual void FinishDrawing();//完成绘制并检查点的位置是否是左上点和右下点,如果不是就更新
};
#endif // MYRECTANGLEITEM_H
#include "myrectangleitem.h"
#include
#include
namespace
{
bool IsGreaterThan(double d1, double d2)//比较d1是否大于d2
{
double eps = 1.0e-6;
double delta = d1 - d2;
if (delta > eps)
{
return true;
}
else
{
return false;
}
}
QRectF makeRect(const QPointF& pt1, const QPointF& pt2)
{
double topLeftX = IsGreaterThan(pt1.x(), pt2.x()) ? pt2.x() : pt1.x();
double topLeftY = IsGreaterThan(pt1.y(), pt2.y()) ? pt2.y() : pt1.y();
double width = qAbs(pt1.x() - pt2.x());
double height = qAbs(pt1.y() - pt2.y());
return QRectF(topLeftX, topLeftY, width, height);
}
}
MyRectangleItem::MyRectangleItem(const QPolygonF& pts,bool drawFinished ,GraphicsBaseItem *parent )
:GraphicsBaseItem(pts, drawFinished, parent)
{
}
ShapeType MyRectangleItem::GetShapeType()
{
return RECTANGLE;
}
void MyRectangleItem::paint(QPainter * painter, const QStyleOptionGraphicsItem * option, QWidget * widget)
{
if (m_pts.isEmpty())
{
return;
}
painter->setPen(Qt::blue);
painter->setBrush(Qt::NoBrush);
painter->setOpacity(1.0);
if (m_drawFinished)
{
if (m_pts.size() == 2)
{
QRectF rect = makeRect(m_pts[0], m_pts[1]);
painter->drawRect(rect);
painter->setBrush(Qt::blue);
for (int i = 0; i < m_pts.size(); i++)
{
painter->drawEllipse(m_pts.at(i), 0.5, 0.5);
}
}
}
else
{
QRectF rect = makeRect(m_pts[0], m_mousePt);//m_mousePt用于追踪鼠标绘制
painter->drawRect(rect);
qDebug() << "unfinish " << m_pts[0] << " , " << m_mousePt;
}
}
bool MyRectangleItem::Contains(const QPointF & pt)
{
if (m_pts.count() != 2)
{
return false;
}
QRectF rect(m_pts[0],m_pts[1]);
bool ret = rect.contains(pt);
return ret;
}
void MyRectangleItem::FinishDrawing()
{
GraphicsBaseItem::FinishDrawing();
if (m_pts.count() == 2)
{
QRectF rect = makeRect(m_pts[0], m_pts[1]);
QPointF topLeft = rect.topLeft();
QPointF bottomRight = rect.bottomRight();
if (topLeft != m_pts[0] || bottomRight != m_pts[1])
{
QPolygonF pts;
pts.push_back(topLeft);
pts.push_back(bottomRight);
m_pts.swap(pts);
}
}
}
多边形
mypolylineitem.h
#ifndef MYPOLYLINEITEM_H
#define MYPOLYLINEITEM_H
#include"mygraphicsbaseitem.h"
class MyPolylineItem : public GraphicsBaseItem
{
public:
MyPolylineItem(const QPolygonF& pts,bool drawFinished = false,GraphicsBaseItem *parent = Q_NULLPTR);
virtual ShapeType GetShapeType();
virtual void paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget) override;
virtual QPainterPath shape() const override;
virtual bool Contains(const QPointF& pt);
};
#endif // MYPOLYLINEITEM_H
#include "mypolylineitem.h"
#include
MyPolylineItem::MyPolylineItem(const QPolygonF& pts,bool drawFinished ,GraphicsBaseItem *parent )
:GraphicsBaseItem(pts, drawFinished, parent)
{
}
ShapeType MyPolylineItem::GetShapeType()
{
return POLYGON;
}
void MyPolylineItem::paint(QPainter * painter, const QStyleOptionGraphicsItem * option, QWidget * widget)
{
if (m_pts.isEmpty())
{
return;
}
painter->setPen(Qt::blue);
painter->setBrush(Qt::NoBrush);
painter->setOpacity(1.0);
if (m_drawFinished)
{
painter->drawPolygon(m_pts);
}
else
{
painter->drawPolyline(m_pts);
painter->drawLine(m_pts.last(), m_mousePt);
}
for (int i = 0; i < m_pts.size(); i++)
{
painter->drawEllipse(m_pts.at(i), 2, 2);
}
}
QPainterPath MyPolylineItem::shape() const
{
QPainterPath path;
if (m_drawFinished)
{
path.addPolygon(m_pts);
}
else
{
for (auto &pt : m_pts)
{
path.lineTo(pt);
}
}
return path;
}
bool MyPolylineItem::Contains(const QPointF & pt)
{
if (m_pts.count() < 3)
{
return false;
}
bool ret = m_pts.containsPoint(pt, Qt::OddEvenFill);
return ret;
}
头文件 globaldefine.h
#ifndef GLOBALDEFINE_H
#define GLOBALDEFINE_H
enum ShapeType
{
UNDEFINED = 0,
CIRCLE, // 圆形
ELLIPSE, // 椭圆形
RECTANGLE, // 矩形
POLYGON //多边形
};
#endif // GLOBALDEFINE_H