QGraphicsItem绘制重叠区域

710 阅读5分钟

效果如下:
在这里插入图片描述
在这里插入图片描述

我通过重写一个继承自QGraphicitem的类来实现上述功能,绘制重叠区域主要通过QPainterPath来实现,核心代码如下:

void myGraphicRectItem::paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget)
{
    QPen mPen= QPen(Qt::yellow);
    painter->setPen(mPen);
    //绘制旋转后的矩形
    painter->drawPolygon(m_oldRectPolygon);
    //绘制旋转圆形
    mPen.setWidth(2);
    mPen.setColor(Qt::green);
    painter->setPen(mPen);
    QPointF pf = getSmallRotateRectCenter(m_oldRectPolygon[0],m_oldRectPolygon[1]);
    QRectF rect = QRectF(pf.x()-10,pf.y()-10,20,20);
    painter->drawEllipse(rect);//绘制圆形
    painter->drawPoint(pf);//绘制点
    //有重叠的情况
    if(!this->scene()->collidingItems(this).isEmpty())
    {
       QPainterPath path,pathOthers;
       QList<QGraphicsItem *> lstcolliItems = this->scene()->collidingItems(this);
       int nColliNum = lstcolliItems.count();
       for(int i = 0;i<nColliNum;i++)
       {
           QGraphicsItem* pTempItem = this->scene()->collidingItems(this)[i];
           QPainterPath tempPath = pTempItem->shape();
           tempPath.translate(pTempItem->pos());//转换到view中的坐标
           pathOthers += tempPath;//记录与本item重叠的item的路径
       }
       path.addPolygon(m_oldRectPolygon);
       path.translate(this->pos());//转换到view中的坐标
       path &= pathOthers;//计算重叠部分的路径path
       path.translate(-this->pos().x(),-this->pos().y());//转换回本Item中的坐标
       QBrush brush(Qt::cyan);
       mPen.setColor(Qt::blue);
       painter->setPen(mPen);
       painter->setBrush(brush);
       painter->drawPath(path);//绘制重叠区域
    }
}

我写的类的paint函数完整代码如下: `void mygraphicCaliperitem::paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget) { QPen mPen; mPen= QPen(Qt::yellow); painter->setPen(mPen); if(m_ShapeType == CALIPER_RECT)// {
//设置笔刷为图片平铺 QImage image(":/maskP"); QBrush brush(image); brush.setStyle(Qt::TexturePattern);//设置平铺模式 painter->setBrush(brush); //绘制旋转后的矩形 if(m_bSelected) painter->setPen(QPen(Qt::green,2)); else painter->setPen(QPen(Qt::green,1)); painter->drawPolygon(m_tCaliRect.m_RECT_Pol); mPen.setColor(Qt::yellow); //绘制右下角顶点矩形 mPen.setWidth(1); painter->setPen(mPen); //绘制右下角顶点矩形 QPainterPath path; path.moveTo(QPointF((m_tCaliRect.m_RECT_BR_Pol[0].x()+m_tCaliRect.m_RECT_BR_Pol[1].x())/2,(m_tCaliRect.m_RECT_BR_Pol[0].y()+m_tCaliRect.m_RECT_BR_Pol[1].y())/2)); path.lineTo(QPointF((m_tCaliRect.m_RECT_BR_Pol[2].x()+m_tCaliRect.m_RECT_BR_Pol[3].x())/2,(m_tCaliRect.m_RECT_BR_Pol[2].y()+m_tCaliRect.m_RECT_BR_Pol[3].y())/2)); path.moveTo(QPointF((m_tCaliRect.m_RECT_BR_Pol[0].x()+m_tCaliRect.m_RECT_BR_Pol[3].x())/2,(m_tCaliRect.m_RECT_BR_Pol[0].y()+m_tCaliRect.m_RECT_BR_Pol[3].y())/2)); path.lineTo(QPointF((m_tCaliRect.m_RECT_BR_Pol[2].x()+m_tCaliRect.m_RECT_BR_Pol[1].x())/2,(m_tCaliRect.m_RECT_BR_Pol[2].y()+m_tCaliRect.m_RECT_BR_Pol[1].y())/2)); painter->setPen(QPen(Qt::yellow,2)); painter->drawPath(path); //绘制投影标记 QPointF pt0 = m_tCaliRect.m_RECT_Shadow_Dir_Pol[0]; QPointF pt1 = QPointF((m_tCaliRect.m_RECT_Shadow_Dir_Pol[2].x()+m_tCaliRect.m_RECT_Shadow_Dir_Pol[3].x())/2,(m_tCaliRect.m_RECT_Shadow_Dir_Pol[2].y()+m_tCaliRect.m_RECT_Shadow_Dir_Pol[3].y())/2); QPointF pt2 = m_tCaliRect.m_RECT_Shadow_Dir_Pol[1]; painter->drawLine(pt0,pt1); painter->drawLine(pt2,pt1); //绘制扫描方向标记 painter->drawPolygon(m_tCaliRect.m_RECT_Scan_Dir_Pol);

    //绘制旋转圆形
    mPen.setWidth(2);
    painter->setPen(mPen);
    QPointF pf = QPointF((m_tCaliRect.m_RECT_Pol[1].x()+m_tCaliRect.m_RECT_Pol[2].x())/2,(m_tCaliRect.m_RECT_Pol[1].y()+m_tCaliRect.m_RECT_Pol[2].y())/2);
    QRectF rect = QRectF(pf.x()-10,pf.y()-10,20,20);
    painter->drawEllipse(rect);//绘制圆形
    painter->drawPoint(pf);//绘制点
    //绘制切变矩形标记
    painter->drawPolygon(m_tCaliRect.m_RECT_Shear_Pol);

    //painter->drawPolygon(m_RECT_Inside_Pol);

// mPen.setColor(Qt::red); // mPen.setWidth(5); // painter->setPen(mPen); // painter->drawPoint(pCross1); // painter->drawPoint(pCross2); // painter->drawPoint(pCross3); // painter->drawPoint(m_RECT.center()); } else if(m_ShapeType == CALIPER_LINE)//直线卡尺 { mPen.setColor(Qt::yellow); mPen.setWidth(2); painter->drawLine(m_CaliLine);

    mPen.setWidth(1);
    int nCount = m_tCaliRectLst.count();
    for(int i = 0;i<nCount;i++)
    {
        //painter->setPen(QPen(Qt::green,1));
        //绘制旋转后的矩形
        if(m_bSelected)
            painter->setPen(QPen(Qt::green,2));
        else
            painter->setPen(QPen(Qt::green,1));
        painter->drawPolygon(m_tCaliRectLst[i].m_RECT_Pol);
        if((nCount+1)/2-1==i)
        {
            //绘制右下角顶点矩形
            QPainterPath path;
            path.moveTo(QPointF((m_tCaliRectLst[i].m_RECT_BR_Pol[0].x()+m_tCaliRectLst[i].m_RECT_BR_Pol[1].x())/2,(m_tCaliRectLst[i].m_RECT_BR_Pol[0].y()+m_tCaliRectLst[i].m_RECT_BR_Pol[1].y())/2));
            path.lineTo(QPointF((m_tCaliRectLst[i].m_RECT_BR_Pol[2].x()+m_tCaliRectLst[i].m_RECT_BR_Pol[3].x())/2,(m_tCaliRectLst[i].m_RECT_BR_Pol[2].y()+m_tCaliRectLst[i].m_RECT_BR_Pol[3].y())/2));
            path.moveTo(QPointF((m_tCaliRectLst[i].m_RECT_BR_Pol[0].x()+m_tCaliRectLst[i].m_RECT_BR_Pol[3].x())/2,(m_tCaliRectLst[i].m_RECT_BR_Pol[0].y()+m_tCaliRectLst[i].m_RECT_BR_Pol[3].y())/2));
            path.lineTo(QPointF((m_tCaliRectLst[i].m_RECT_BR_Pol[2].x()+m_tCaliRectLst[i].m_RECT_BR_Pol[1].x())/2,(m_tCaliRectLst[i].m_RECT_BR_Pol[2].y()+m_tCaliRectLst[i].m_RECT_BR_Pol[1].y())/2));
            painter->setPen(QPen(Qt::yellow,2));
            painter->drawPath(path);
            //绘制投影标记
            painter->setPen(QPen(Qt::yellow,1));
            QPointF pt0 = m_tCaliRectLst[i].m_RECT_Shadow_Dir_Pol[0];
            QPointF pt1 = QPointF((m_tCaliRectLst[i].m_RECT_Shadow_Dir_Pol[2].x()+m_tCaliRectLst[i].m_RECT_Shadow_Dir_Pol[3].x())/2,(m_tCaliRectLst[i].m_RECT_Shadow_Dir_Pol[2].y()+m_tCaliRectLst[i].m_RECT_Shadow_Dir_Pol[3].y())/2);
            QPointF pt2 = m_tCaliRectLst[i].m_RECT_Shadow_Dir_Pol[1];
            painter->drawLine(pt0,pt1);
            painter->drawLine(pt2,pt1);
            //绘制扫描方向标记
            painter->drawPolygon(m_tCaliRectLst[i].m_RECT_Scan_Dir_Pol);

#ifdef ROTATE_AND_SHEAR //绘制旋转圆形 painter->setPen(QPen(Qt::yellow,2)); QPointF pf = QPointF((m_tCaliRectLst[i].m_RECT_Pol[1].x()+m_tCaliRectLst[i].m_RECT_Pol[2].x())/2,(m_tCaliRectLst[i].m_RECT_Pol[1].y()+m_tCaliRectLst[i].m_RECT_Pol[2].y())/2); QRectF rect = QRectF(pf.x()-10,pf.y()-10,20,20); painter->drawEllipse(rect);//绘制圆形 painter->drawPoint(pf);//绘制点 //绘制切变矩形标记 painter->drawPolygon(m_tCaliRectLst[i].m_RECT_Shear_Pol); #endif } } mPen= QPen(Qt::red); mPen.setWidth(4); painter->setPen(mPen); painter->drawPoint(m_CaliLine.p1()); painter->drawPoint(m_CaliLine.p2()); // painter->drawPolygon(m_LineBodyPol);//直线上下各10像素范围内的矩形区域 // painter->drawEllipse(m_LineP1); // painter->drawEllipse(m_LineP2); } else if(m_ShapeType == CALIPER_CIRCLE)//圆形卡尺 { int nCount = m_tCaliRectLst.count(); for(int i = 0;i<nCount;i++) { //绘制旋转后的矩形 if(m_bSelected) painter->setPen(QPen(Qt::green,2)); else painter->setPen(QPen(Qt::green,1)); painter->drawPolygon(m_tCaliRectLst[i].m_RECT_Pol);

        //绘制右下角顶点矩形十字
        if((nCount+1)/2-1==i)
        {
           QPainterPath path;
           path.moveTo(QPointF((m_tCaliRectLst[i].m_RECT_BR_Pol[0].x()+m_tCaliRectLst[i].m_RECT_BR_Pol[1].x())/2,(m_tCaliRectLst[i].m_RECT_BR_Pol[0].y()+m_tCaliRectLst[i].m_RECT_BR_Pol[1].y())/2));
           path.lineTo(QPointF((m_tCaliRectLst[i].m_RECT_BR_Pol[2].x()+m_tCaliRectLst[i].m_RECT_BR_Pol[3].x())/2,(m_tCaliRectLst[i].m_RECT_BR_Pol[2].y()+m_tCaliRectLst[i].m_RECT_BR_Pol[3].y())/2));
           path.moveTo(QPointF((m_tCaliRectLst[i].m_RECT_BR_Pol[0].x()+m_tCaliRectLst[i].m_RECT_BR_Pol[3].x())/2,(m_tCaliRectLst[i].m_RECT_BR_Pol[0].y()+m_tCaliRectLst[i].m_RECT_BR_Pol[3].y())/2));
           path.lineTo(QPointF((m_tCaliRectLst[i].m_RECT_BR_Pol[2].x()+m_tCaliRectLst[i].m_RECT_BR_Pol[1].x())/2,(m_tCaliRectLst[i].m_RECT_BR_Pol[2].y()+m_tCaliRectLst[i].m_RECT_BR_Pol[1].y())/2));
           painter->setPen(QPen(Qt::yellow,2));
           painter->drawPath(path);
           //绘制扫描方向标记
           painter->setPen(QPen(Qt::yellow,1));
           painter->drawPolygon(m_tCaliRectLst[i].m_RECT_Scan_Dir_Pol);
        }
    }
    //painter->drawEllipse(QRectF(m_CircleCenter.x()-m_radius,m_CircleCenter.y()-m_radius,m_radius*2,m_radius*2));
    painter->setPen(QPen(Qt::red,4));
    painter->drawPoint(m_CircleP1);
    painter->drawPoint(m_CircleP2);
    painter->drawPoint(m_CircleP3);
    qreal angle1 = atan2(m_CircleP1.x()-m_CircleCenter.x(),m_CircleP1.y()-m_CircleCenter.y())*180/M_PI-90;
    //qDebug()<<"angle1:"<<angle1<<endl;
    if(angle1<0)
        angle1 = 360+angle1;
    if(angle1>360)
        angle1 = angle1-360;
    qreal angle3 = atan2(m_CircleP3.x()-m_CircleCenter.x(),m_CircleP3.y()-m_CircleCenter.y())*180/M_PI-90;
    //qDebug()<<"angle3:"<<angle3<<endl;
    if(angle3<0)
        angle3 = 360+angle3;
    if(angle3>360)
        angle3 = angle3-360;
    qreal angle0 = angle3-angle1;
    if(angle0<0)
        angle0 = 360+angle0;
    if(angle0>360)
        angle0 = angle0-360;
    painter->setPen(QPen(Qt::yellow,1));
    qreal s= (m_CircleP1.x() - m_CircleP3.x()) * (m_CircleP2.y() - m_CircleP3.y()) - (m_CircleP2.x() - m_CircleP3.x())*(m_CircleP1.y() - m_CircleP3.y());//向量p3p1和p3p2的叉积
    if(s>0)//叉积方向决定了弧形是内弧还是外弧
    {
        painter->drawArc(m_CircleRect,(int)angle3*16,(int)(360-angle0)*16);
    }
    else
    {
        painter->drawArc(m_CircleRect,(int)angle1*16,(int)angle0*16);
    }
    //qDebug()<<"angle1:"<<angle1<<"angle3:"<<angle3<<"angle0:"<<angle0<<"s:"<<s;
    //绘制补全圆使用的双向箭头
    QPainterPath path = getFillCircleArrow(m_CircleP1,m_CircleCenter,m_radius,10);
    painter->setPen(QPen(Qt::green,1));
    painter->drawPath(path);
    path = getFillCircleArrow(m_CircleP3,m_CircleCenter,m_radius,10);
    painter->drawPath(path);

}
else if(m_ShapeType == C_CIRCLE)//圆形
{
    if(m_bSelected)
        painter->setPen(QPen(Qt::green,2));
    else
        painter->setPen(QPen(Qt::green,1));
    painter->drawEllipse(m_tCircle.m_RECT);
    //绘制缩放用的x标记
    QPainterPath path;
    path.moveTo(QPointF((m_tCircle.m_RECT_BR_Pol[0].x()+m_tCircle.m_RECT_BR_Pol[1].x())/2,(m_tCircle.m_RECT_BR_Pol[0].y()+m_tCircle.m_RECT_BR_Pol[1].y())/2));
    path.lineTo(QPointF((m_tCircle.m_RECT_BR_Pol[2].x()+m_tCircle.m_RECT_BR_Pol[3].x())/2,(m_tCircle.m_RECT_BR_Pol[2].y()+m_tCircle.m_RECT_BR_Pol[3].y())/2));
    path.moveTo(QPointF((m_tCircle.m_RECT_BR_Pol[0].x()+m_tCircle.m_RECT_BR_Pol[3].x())/2,(m_tCircle.m_RECT_BR_Pol[0].y()+m_tCircle.m_RECT_BR_Pol[3].y())/2));
    path.lineTo(QPointF((m_tCircle.m_RECT_BR_Pol[2].x()+m_tCircle.m_RECT_BR_Pol[1].x())/2,(m_tCircle.m_RECT_BR_Pol[2].y()+m_tCircle.m_RECT_BR_Pol[1].y())/2));
    painter->setPen(QPen(Qt::yellow,2));
    painter->drawPath(path);
}
else if(m_ShapeType == C_ELLIPSE)//椭圆
{
    if(m_bSelected)
        painter->setPen(QPen(Qt::green,2));
    else
        painter->setPen(QPen(Qt::green,1));
    //绘制旋转后的圆形
    QTransform trans0;
    QPainterPath path0;
    trans0.translate(m_tEllipse.m_RotateCenter.x(),m_tEllipse.m_RotateCenter.y());
    trans0.rotate(m_tEllipse.m_RotateAngle,Qt::ZAxis);
    trans0.translate(-m_tEllipse.m_RotateCenter.x(),-m_tEllipse.m_RotateCenter.y());
    path0.addEllipse(m_tEllipse.m_RECT);
    path0 = trans0.map(path0);//将pathTemp旋转m_RotateAngle角度
    painter->drawPath(path0);//drawPolygon(m_RECT_Pol);
    //绘制旋转圆形标记
    mPen.setWidth(2);
    mPen.setColor(Qt::green);
    painter->setPen(mPen);
    QPointF pf = getVeritacalLinePoint(m_tEllipse.m_RECT_Pol[0],m_tEllipse.m_RECT_Pol[1]);
    QRectF rect = QRectF(pf.x()-10,pf.y()-10,20,20);
    painter->drawEllipse(rect);//绘制圆形
    painter->drawPoint(pf);//绘制点
    //绘制双向箭头
    painter->setPen(QPen(Qt::green,1));
    painter->drawPath(getScaleEllipseArror(m_tEllipse.m_RECT_Pol));
}
else if(m_ShapeType == C_LINE)
{
    //绘制旋转后的矩形
    if(m_bSelected)
        painter->setPen(QPen(Qt::green,2));
    else
        painter->setPen(QPen(Qt::green,1));
    QPainterPath path0;
    path0.moveTo(m_Line.p1());
    path0.lineTo(m_Line.p2());
    painter->drawPath(path0);
    //绘制直线的两端点标记
    painter->setPen(QPen(Qt::red,4));
    painter->drawPoint(m_Line.p1());
    painter->drawPoint(m_Line.p2());


}
else if(m_ShapeType == C_MASK)
{
    QRect nRect(0,0,2000, 2000);
    QPixmap littleImage;
    littleImage = m_BlackWhiteBigImg.copy(nRect);
    QPixmap pix = pixmapToPath(littleImage);
    painter->setOpacity(0.2);
    painter->drawPixmap(nRect,pix);

// qDebug()<<"option->rect:"<rect; // qDebug()<<"m_Line:"<<m_Line.p1()<<m_Line.p2(); } else if(m_ShapeType == C_POLYGON) { //绘制多边形 if(m_bSelected) painter->setPen(QPen(Qt::green,2)); else painter->setPen(QPen(Qt::green,1)); painter->drawPolygon(m_oldPolygon); //绘制每个点 painter->setPen(QPen(Qt::red,4)); for(int i = 0;i<m_oldPolygon.size();i++) { painter->drawPoint(m_oldPolygon[i]); } }

//有重叠的情况
if(!this->scene()->collidingItems(this).isEmpty())
{
   QPainterPath path,pathOthers;
   QList<QGraphicsItem *> lstcolliItems = this->scene()->collidingItems(this);
   int nColliNum = lstcolliItems.count();
   for(int i = 0;i<nColliNum;i++)
   {
       if(lstcolliItems[i]->type()==UserType+1)
       {
           mygraphicCaliperitem* pTempItem = (mygraphicCaliperitem*)lstcolliItems[i];
           if(pTempItem->zValue()==0)
           {
               QPainterPath tempPath = pTempItem->getCollideShape();
               tempPath.translate(pTempItem->pos());//转换到view中的坐标
               pathOthers += tempPath;//记录与本item重叠的item的路径
           }
       }
   }
   path=getCollideShape();
   path.translate(this->pos());//转换到view中的坐标
   path &= pathOthers;//计算重叠部分的路径path
   path.translate(-this->pos().x(),-this->pos().y());//转换回本Item中的坐标
   //QBrush brush(Qt::cyan);
   //设置笔刷为图片平铺
   QImage image(":/maskP");
   QBrush brush(image);
   brush.setStyle(Qt::TexturePattern);//设置平铺模式
   mPen.setColor(Qt::blue);
   painter->setPen(mPen);
   painter->setBrush(brush);
   painter->drawPath(path);//绘制重叠区域
}

}`