入门
先看一个简单的例子
#include"mainwindow.h"#include"ui_mainwindow.h"#include<QGraphicsScene>#include<QGraphicsView>MainWindow::MainWindow(QWidget *parent):QMainWindow(parent),ui(new Ui::MainWindow){
ui->setupUi(this);init();}MainWindow::~MainWindow(){delete ui;}voidMainWindow::init(){
QGraphicsScene *pScene =newQGraphicsScene();
pScene->addText("Hello, world!");
QGraphicsView *pView =newQGraphicsView(pScene,this);}
效果:
- QGraphicsView
- QCustomQGraphicsScene
- QGraphicsItem
实时绘制
需求:至少有两种图形需要绘制
画一个图元的逻辑
在界面上(LabelGraphicsView类)需要有一个成员变量(m_graphicsBaseItem )负责当前图元的绘画。这个成员变量可以画多种类型的图元。
设计一个基类 GraphicsBaseItem (继承自QGraphicsItem),再扩展两个子类:
- MyPolylineItem (继承自GraphicsBaseItem ): 绘制多边形,自定义paint函数
- MyRectangleItem(继承自GraphicsBaseItem ):绘制长方形,自定义paint函数. (调用update后,会调用paint函数)
需要画矩形时,就把MyRectangleItem 赋值到GraphicsBaseItem ,调用paint函数绘制。需要画多边形时,使用MyRectangleItem
每个图元类自己内部维护一个画图状态(m_drawFinished)。如画图未完成,则可以继续加点,可以更新实时动态等。
画多个图元的逻辑
成员变量(m_graphicsBaseItem )负责当前图元的绘画,画图完成之后,更新画图状态(m_drawFinished),并重新new一个相同的图元,添加当场景中。清空成员变量(m_graphicsBaseItem )的值,等待下一个图元的绘制
GraphicsBaseItem 类
至少需要考虑一下场景:
- 画矩形框:鼠标拖动实时显示矩形的形状。那么就涉及到: (1)矩形框的起始位置 (2)当前鼠标位置 (3)矩形最终位置 所以鼠标按下时,添加第一个点,拖动时更新鼠标当前位置m_mousePt,并绘图。鼠标松开时,加入最后一个点。所以还需要判断当前是否在绘图(bool m_drawFinished;)
- 画多边形: (1)点是否有重复 (2)需要一个闭合函数:比如最后一个点自动连接到第一个点( int GetNearestVertex(const QPointF& pt);)
- 图行点击时高亮:QColor m_color; QColor m_lineHighlightColor;
#ifndefGRAPHICSBASEITEM_H#defineGRAPHICSBASEITEM_H#include<QGraphicsItem>#include"globaldefine.h"classGraphicsBaseItem:publicQGraphicsItem{public:GraphicsBaseItem(const QPolygonF& pts,bool drawFinished =false,
QGraphicsItem *parent = Q_NULLPTR);// 查看图形类型,比如矩形,多边形virtual ShapeType GetShapeType()=0;// 查看是否包含这个点virtualboolContains(const QPointF& pt)=0;//是否完成了绘图(鼠标拖动场景下使用,或者多边形绘制)virtualvoidFinishDrawing();//添加点,获取点voidAddPoint(const QPointF& point);intGetPointCounts();boolGetPoint(int id, QPointF& pt);
QPolygonF GetPoints();boolRemoveLastPoint();intGetNearestVertex(const QPointF& pt);//设置当前鼠标位置voidSetMousePt(const QPointF& mousePt);//重置voidReset();//是否被选中voidSetSelected(bool isSelected);virtual QRectF boundingRect()constoverride;protected:
QPolygonF m_pts;//闭合曲线首尾点无需重复存储
QPointF m_mousePt;//画图时鼠标当前位置点bool m_selected;//是否被选中bool m_drawFinished;//是否完成绘图};#endif// GRAPHICSBASEITEM_H
MyRectangleItem类
主要实现该类的绘图功能 paint
#ifndefMYRECTANGLEITEM_H#defineMYRECTANGLEITEM_H#include"globaldefine.h"#include"mygraphicsbaseitem.h"classMyRectangleItem:publicGraphicsBaseItem{public:MyRectangleItem(const QPolygonF& pts,bool drawFinished =false,GraphicsBaseItem *parent = Q_NULLPTR);virtual ShapeType GetShapeType();//绘图 在updata后调用 MyPolylineItemvirtualvoidpaint(QPainter *painter,const QStyleOptionGraphicsItem *option, QWidget *widget)override;virtualboolContains(const QPointF& pt);virtualvoidFinishDrawing();//完成绘制并检查点的位置是否是左上点和右下点,如果不是就更新};#endif// MYRECTANGLEITEM_H
具体实现
#include"myrectangleitem.h"#include<QPainter>#include<QDebug>namespace{boolIsGreaterThan(double d1,double d2)//比较d1是否大于d2{double eps =1.0e-6;double delta = d1 - d2;if(delta > eps){returntrue;}else{returnfalse;}}
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());returnQRectF(topLeftX, topLeftY, width, height);}}MyRectangleItem::MyRectangleItem(const QPolygonF& pts,bool drawFinished ,GraphicsBaseItem *parent ):GraphicsBaseItem(pts, drawFinished, parent){}
ShapeType MyRectangleItem::GetShapeType(){return RECTANGLE;}voidMyRectangleItem::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;}}boolMyRectangleItem::Contains(const QPointF & pt){if(m_pts.count()!=2){returnfalse;}
QRectF rect(m_pts[0],m_pts[1]);bool ret = rect.contains(pt);return ret;}voidMyRectangleItem::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 类
多边形类
MyPolylineItem
多边形由一系列点组成,起始点和终止点比较重要
需要设置终止方案。
#ifndefMYPOLYLINEITEM_H#defineMYPOLYLINEITEM_H#include"mygraphicsbaseitem.h"classMyPolylineItem:publicGraphicsBaseItem{public:MyPolylineItem(const QPolygonF& pts,bool drawFinished =false,GraphicsBaseItem *parent = Q_NULLPTR);virtual ShapeType GetShapeType();virtualvoidpaint(QPainter *painter,const QStyleOptionGraphicsItem *option, QWidget *widget)override;virtual QPainterPath shape()constoverride;virtualboolContains(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 如果释放的点不是第一个点的位置,则认为是一个完整的矩形,添加最后一个点完成绘制。否则清空所有点
多边形画法
问题:
- 什么事件加点?mousePressEvent or mouseReleaseEvent ? 考虑到有人会在按下鼠标时后悔,再拖动鼠标到正确位置释放,所以选择在mouseReleaseEvent 事件中加点
- 什么时候标记第一个点:判断当前没有图形绘制时,也没有其他操作时,且触发了mouseReleaseEvent
- 什么情况完成绘图:最后一个点和第一个点重合时,结束绘画
所以在界面类中,我们需要标记状态
- 绘图
- 移动
- 默认
界面LabelGraphicsView
#include"LabelGraphicsView.h"#include"myrectangleitem.h"#include<QMouseEvent>LabelGraphicsView::LabelGraphicsView(){init();
QVector<QPointF> pts;
m_GraphicsBaseItem =newMyRectangleItem(pts,false);}LabelGraphicsView::~LabelGraphicsView(){}voidLabelGraphicsView::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);}voidLabelGraphicsView::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);}voidLabelGraphicsView::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 =newMyRectangleItem(pts,true);
m_graphicsScene.addItem(newItem);
m_GraphicsBaseItem->Reset();}//实时获取鼠标最新位置并绘图 voidLabelGraphicsView::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<QtWidgets/QApplication>intmain(int argc,char*argv[]){
QApplication a(argc, argv);
LabelImg w;
w.show();return a.exec();}
ui 界面
LabelImg.h
#pragmaonce#include"LabelGraphicsView.h"#include<QtWidgets/QMainWindow>#include"ui_LabelImg.h"classLabelImg:publicQMainWindow{
Q_OBJECT
public:LabelImg(QWidget *parent = Q_NULLPTR);private:voidinit();public slots:voidSlotRectangleButtonClicked();voidSlotPolylineButtonClicked();private:
Ui::LabelImgClass ui;
LabelGraphicsView * m_graphicsView =nullptr;};
#include"LabelImg.h"#include<QVBoxLayout>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()));}voidLabelImg::init(){
QVBoxLayout *vBoxLayout =new QVBoxLayout;
ui.widget->setLayout(vBoxLayout);
vBoxLayout->setMargin(2);
vBoxLayout->setSpacing(2);
m_graphicsView =newLabelGraphicsView();
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);}voidLabelImg::SlotRectangleButtonClicked(){
m_graphicsView->setDrawRectangleModule();}voidLabelImg::SlotPolylineButtonClicked(){
m_graphicsView->setDrawPolylineModule();}
LabelGraphicsView.h
#pragmaonce#include<QGraphicsView>#include"mygraphicsbaseitem.h"#include"myrectangleitem.h"#include"mypolylineitem.h"enumProcessMode{
DEFAULT =0,// 默认模式
DRAW,//绘图模式
MOVE //移动模式};classLabelGraphicsView:publicQGraphicsView{public:LabelGraphicsView();~LabelGraphicsView();voidsetDrawRectangleModule();voidsetDrawPolylineModule();virtualvoidmousePressEvent(QMouseEvent *event)override;virtualvoidmouseReleaseEvent(QMouseEvent *event)override;virtualvoidmouseMoveEvent(QMouseEvent *event)override;private:voidinit();boolisSamePoint(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<QMouseEvent>LabelGraphicsView::LabelGraphicsView(){init();}LabelGraphicsView::~LabelGraphicsView(){}voidLabelGraphicsView::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 =newMyPolylineItem(pts,false);
QVector<QPointF> rpts;
m_RectangleItem =newMyRectangleItem(rpts,false);
m_graphicsScene.addItem(m_GraphicsBaseItem);}voidLabelGraphicsView::setDrawRectangleModule(){if(m_GraphicsBaseItem){
m_GraphicsBaseItem->Reset();
m_GraphicsBaseItem =nullptr;}if(!m_RectangleItem){
QVector<QPointF> rpts;
m_RectangleItem =newMyRectangleItem(rpts,false);}
m_GraphicsBaseItem =m_RectangleItem;
m_graphicsScene.addItem(m_GraphicsBaseItem);}voidLabelGraphicsView::setDrawPolylineModule(){if(m_GraphicsBaseItem){
m_GraphicsBaseItem->Reset();
m_GraphicsBaseItem =nullptr;}if(!m_PolylineItem){
QVector<QPointF> pts;
m_PolylineItem =newMyPolylineItem(pts,false);}
m_GraphicsBaseItem = m_PolylineItem;
m_graphicsScene.addItem(m_GraphicsBaseItem);}voidLabelGraphicsView::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);}voidLabelGraphicsView::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 =newMyRectangleItem(pts,true);
m_graphicsScene.addItem(newItem);//m_graphicsScene.removeItem(m_GraphicsBaseItem);
m_GraphicsBaseItem->Reset();}elseif(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 =newMyPolylineItem(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);//不写这行图元会错位}//实时获取鼠标最新位置并绘图 voidLabelGraphicsView::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);}boolLabelGraphicsView::isSamePoint(QPointF p1, QPointF p2){
QPointF dif = p1 - p2;float distance = dif.manhattanLength();//方圆5个像素点内if(distance <=5){returntrue;}else{returnfalse;}}
图元
mygraphicsbaseitem.h
#ifndefGRAPHICSBASEITEM_H#defineGRAPHICSBASEITEM_H#include<QGraphicsItem>#include"globaldefine.h"classGraphicsBaseItem:publicQGraphicsItem{public:GraphicsBaseItem(const QPolygonF& pts,bool drawFinished =false,
QGraphicsItem *parent = Q_NULLPTR);~GraphicsBaseItem();// 查看图形类型,比如矩形,多边形virtual ShapeType GetShapeType()=0;// 查看是否包含这个点virtualboolContains(const QPointF& pt)=0;//是否完成了绘图(鼠标拖动场景下使用,或者多边形绘制)virtualvoidFinishDrawing();virtualvoidpaint(QPainter *painter,const QStyleOptionGraphicsItem *option, QWidget *widget)=0;//添加点,获取点voidAddPoint(const QPointF& point);intGetPointCounts();boolGetPoint(int id, QPointF& pt);
QPolygonF GetPoints();boolRemoveLastPoint();intGetNearestVertex(const QPointF& pt);//设置当前鼠标位置voidSetMousePt(const QPointF& mousePt);//重置voidReset();//是否被选中voidSetSelected(bool isSelected);virtual QRectF boundingRect()constoverride;protected:
QPolygonF m_pts;//闭合曲线首尾点无需重复存储
QPointF m_mousePt;//画图时鼠标当前位置点bool m_selected;//是否被选中bool m_drawFinished;//是否完成绘图};#endif// GRAPHICSBASEITEM_H
#include"mygraphicsbaseitem.h"#include<QDebug>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(){}voidGraphicsBaseItem::FinishDrawing(){
m_drawFinished =true;}voidGraphicsBaseItem::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);}intGraphicsBaseItem::GetPointCounts(){return m_pts.count();}boolGraphicsBaseItem::GetPoint(int id, QPointF& pt){if(id >=0&& id < m_pts.size()){
pt = m_pts[id];returntrue;}returnfalse;}
QPolygonF GraphicsBaseItem::GetPoints(){return m_pts;}boolGraphicsBaseItem::RemoveLastPoint(){if(!m_pts.isEmpty()){
m_pts.removeLast();returntrue;}returnfalse;}intGraphicsBaseItem::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;}voidGraphicsBaseItem::SetMousePt(const QPointF & mousePt){
m_mousePt = mousePt;}voidGraphicsBaseItem::Reset(){
m_pts.clear();
m_drawFinished =false;}voidGraphicsBaseItem::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());}}returnQRectF(leftTop, rightBottom);}//这行不写,m_graphicsScene.addItem(newItem)时,m_pts为空会直接崩掉returnQRectF();}
矩形
myrectangleitem.h
#ifndefMYRECTANGLEITEM_H#defineMYRECTANGLEITEM_H#include"globaldefine.h"#include"mygraphicsbaseitem.h"classMyRectangleItem:publicGraphicsBaseItem{public:MyRectangleItem(const QPolygonF& pts,bool drawFinished =false,GraphicsBaseItem *parent = Q_NULLPTR);virtual ShapeType GetShapeType();//绘图 在updata后调用 paintvirtualvoidpaint(QPainter *painter,const QStyleOptionGraphicsItem *option, QWidget *widget)override;virtualboolContains(const QPointF& pt);virtualvoidFinishDrawing();//完成绘制并检查点的位置是否是左上点和右下点,如果不是就更新};#endif// MYRECTANGLEITEM_H
#include"myrectangleitem.h"#include<QPainter>#include<QDebug>namespace{boolIsGreaterThan(double d1,double d2)//比较d1是否大于d2{double eps =1.0e-6;double delta = d1 - d2;if(delta > eps){returntrue;}else{returnfalse;}}
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());returnQRectF(topLeftX, topLeftY, width, height);}}MyRectangleItem::MyRectangleItem(const QPolygonF& pts,bool drawFinished ,GraphicsBaseItem *parent ):GraphicsBaseItem(pts, drawFinished, parent){}
ShapeType MyRectangleItem::GetShapeType(){return RECTANGLE;}voidMyRectangleItem::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;}}boolMyRectangleItem::Contains(const QPointF & pt){if(m_pts.count()!=2){returnfalse;}
QRectF rect(m_pts[0],m_pts[1]);bool ret = rect.contains(pt);return ret;}voidMyRectangleItem::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
#ifndefMYPOLYLINEITEM_H#defineMYPOLYLINEITEM_H#include"mygraphicsbaseitem.h"classMyPolylineItem:publicGraphicsBaseItem{public:MyPolylineItem(const QPolygonF& pts,bool drawFinished =false,GraphicsBaseItem *parent = Q_NULLPTR);virtual ShapeType GetShapeType();virtualvoidpaint(QPainter *painter,const QStyleOptionGraphicsItem *option, QWidget *widget)override;virtual QPainterPath shape()constoverride;virtualboolContains(const QPointF& pt);};#endif// MYPOLYLINEITEM_H
#include"mypolylineitem.h"#include<QPainter>MyPolylineItem::MyPolylineItem(const QPolygonF& pts,bool drawFinished ,GraphicsBaseItem *parent ):GraphicsBaseItem(pts, drawFinished, parent){}
ShapeType MyPolylineItem::GetShapeType(){return POLYGON;}voidMyPolylineItem::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;}boolMyPolylineItem::Contains(const QPointF & pt){if(m_pts.count()<3){returnfalse;}bool ret = m_pts.containsPoint(pt, Qt::OddEvenFill);return ret;}
头文件 globaldefine.h
#ifndefGLOBALDEFINE_H#defineGLOBALDEFINE_HenumShapeType{
UNDEFINED =0,
CIRCLE,// 圆形
ELLIPSE,// 椭圆形
RECTANGLE,// 矩形
POLYGON //多边形};#endif// GLOBALDEFINE_H
版权归原作者 蜉蝣之翼❉ 所有, 如有侵权,请联系我们删除。