0


qt QGraphicsView 绘制多种图形

入门

先看一个简单的例子

#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),再扩展两个子类:

  1. MyPolylineItem (继承自GraphicsBaseItem ): 绘制多边形,自定义paint函数
  2. MyRectangleItem(继承自GraphicsBaseItem ):绘制长方形,自定义paint函数. (调用update后,会调用paint函数)

需要画矩形时,就把MyRectangleItem 赋值到GraphicsBaseItem ,调用paint函数绘制。需要画多边形时,使用MyRectangleItem
每个图元类自己内部维护一个画图状态(m_drawFinished)。如画图未完成,则可以继续加点,可以更新实时动态等。

画多个图元的逻辑

成员变量(m_graphicsBaseItem )负责当前图元的绘画,画图完成之后,更新画图状态(m_drawFinished),并重新new一个相同的图元,添加当场景中。清空成员变量(m_graphicsBaseItem )的值,等待下一个图元的绘制

GraphicsBaseItem 类

至少需要考虑一下场景:

  1. 画矩形框:鼠标拖动实时显示矩形的形状。那么就涉及到: (1)矩形框的起始位置 (2)当前鼠标位置 (3)矩形最终位置 所以鼠标按下时,添加第一个点,拖动时更新鼠标当前位置m_mousePt,并绘图。鼠标松开时,加入最后一个点。所以还需要判断当前是否在绘图(bool m_drawFinished;)
  2. 画多边形: (1)点是否有重复 (2)需要一个闭合函数:比如最后一个点自动连接到第一个点( int GetNearestVertex(const QPointF& pt);)
  3. 图行点击时高亮: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

绘图的逻辑

思路

纵向是三个鼠标事件

  1. virtual void mousePressEvent(QMouseEvent *event) override; virtual
  2. void mouseReleaseEvent(QMouseEvent *event) override; virtual void
  3. mouseMoveEvent(QMouseEvent *event) override;

横向是两种图元

  1. 矩形
  2. 多边形

矩形画法

按下鼠标左键,不放开拖动到目标位置,放开。于是按照时间顺序依次触发

  1. mousePressEvent 添加第一个点
  2. mouseMoveEvent 界面实时更新鼠标位置 画矩形
  3. mouseReleaseEvent 如果释放的点不是第一个点的位置,则认为是一个完整的矩形,添加最后一个点完成绘制。否则清空所有点

多边形画法

问题:

  1. 什么事件加点?mousePressEvent or mouseReleaseEvent ? 考虑到有人会在按下鼠标时后悔,再拖动鼠标到正确位置释放,所以选择在mouseReleaseEvent 事件中加点
  2. 什么时候标记第一个点:判断当前没有图形绘制时,也没有其他操作时,且触发了mouseReleaseEvent
  3. 什么情况完成绘图:最后一个点和第一个点重合时,结束绘画

所以在界面类中,我们需要标记状态

  1. 绘图
  2. 移动
  3. 默认

界面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
标签: qt ui c++

本文转载自: https://blog.csdn.net/fuyouzhiyi/article/details/124465742
版权归原作者 蜉蝣之翼❉ 所有, 如有侵权,请联系我们删除。

“qt QGraphicsView 绘制多种图形”的评论:

还没有评论