重写QGraphicItems的类,拖动缩放对象的时候偶尔接收不到鼠标点击事件

264 阅读4分钟

我写了一个类,继承自QGraphicItems
然后重写了 paint(), boundingRect() 和shape() 方法
paint()绘制的图形如下图所示:
在这里插入图片描述
shape()中返回的是上面红线标出的区域
boundingRect() 中返回的是上面红线区域的最小外接矩形

然后我重写了mousePressEvent(),mouseMoveEvent(),mouseReleaseEvent()以实现鼠标按住上面任意一个顶点可进行图形的拉伸,如下图所示:
在这里插入图片描述
在这个过程中,会出现一个问题,就是鼠标拖动顶点移动几次之后,图像会接收不到鼠标点击事件,也就是再也无法拉伸上面这个图像了。
研究了半天发现,问题出在qt的QGraphicsScene场景上面:
我们在缩放QGraphicsScene内部的QGraphicItems的时候,QGraphicsScene会自动判定是否需要重新获取QGraphicItems的边框(也就是调用QGraphicItems内的boundingRect() 和shape()),换句话说,QGraphicItems内的boundingRect() 和shape()函数是否被调用,全看QGraphicsScene的心情。
而我们在缩放图形的时候,往往会把图形拉伸到超过原先的边框区域,这个时候如果QGraphicsScene不调用boundingRect() 和shape()函数的话,就会出错。
出错形式表现为:我们拉伸完item的时候,再把鼠标移上去,却触发不了item的鼠标事件
解决方法:
在拉伸的时候,也就是在mouseMoveEvent()函数内,先执行

prepareGeometryChange()

方法,通知QGraphicsScene:老子要重绘item了,你给我准备好重新获取item的边框!
然后再写根据鼠标位置重置item大小的代码,然后执行

scene()->update();//刷星界面

mousemove函数代码如下:

void mygraphicCaliperitem::mouseMoveEvent(QGraphicsSceneMouseEvent *event)
```

```
{
```

```
    prepareGeometryChange();
```

```
    if(m_ShapeType == CALIPER_RECT)//矩形
```

```
    {
```

```
        if(m_StateFlag == CALI_RECT_ROTATE)
```

```
        {
```

```
           qreal nRotateAngle = atan2((event->pos().x()-m_tCaliRect.m_RotateCenter.x()),(event->pos().y()-m_tCaliRect.m_RotateCenter.y()))*180/M_PI;
```

```
           SetRotate(90-nRotateAngle);
```

```
           //qDebug()<<nRotateAngle;
```

```
        }
```

```
        else if(m_StateFlag == CALI_RECT_MOVE)
```

```
        {
```

```
            QPointF point = (event->pos() - m_startPos);
```

```
            moveBy(point.x(), point.y());
```

```
            scene()->update();
```

```
        }
```

```
        else if(m_StateFlag == CALI_RECT_SHEAR)//控制矩形斜切
```

```
        {
```

```
            QPointF pc,p0,p1,p2,p3;//,pCross1,pCross2;
```

```
            pc = m_tCaliRect.m_RotateCenter;
```

```
            p0 = m_tCaliRect.m_RECT_Pol[0];
```

```
            p1 = m_tCaliRect.m_RECT_Pol[1];
```

```
            p2 = m_tCaliRect.m_RECT_Pol[2];
```

```
            p3 = m_tCaliRect.m_RECT_Pol[3];
```

```
            if(!get2CrossPt(p0,p1,p2,pc,event->pos(),pCross1,pCross2))
```

```
                return;
```

```
            //过pc做p2p3的垂线line3,line3方程为y=k3x+b3,line3与p2,p3交点为pCross3
```

```
            qreal k3,b3,k4,b4;
```

```
            qreal x3,y3;//pCross3(x3,y3),//y3=k3x3+b3,y3=k4x3+b4,求x3,y3
```

```
            if(p3.y()==p2.y())
```

```
            {
```

```
                //k3不存在,lin3为x=pc.x()
```

```
                //直线p2p3为y=k4x+b4
```

```
                if(p3.x()==p2.x())
```

```
                {
```

```
                    //k4不存在,直线p2p3为x=p2.x()
```

```
                    return;
```

```
                }
```

```
                else
```

```
                {
```

```
                    k4=(p3.y()-p2.y())/(p3.x()-p2.x());
```

```
                    b4 = p2.y()-k4*p2.x();
```

```
                    //TODO:求(x3,y3)
```

```
                    x3 = pc.x();
```

```
                    y3 = k4*x3+b4;
```

```
                }
```

```
            }
```

```
            else
```

```
            {
```

```
                k3 = (p2.x()-p3.x())/(p3.y()-p2.y());
```

```
                b3=pc.y()-k3*pc.x();
```

```
                //直线p2p3为y=k4x+b4
```

```
                if(p3.x()==p2.x())
```

```
                {
```

```
                    //k4不存在,直线p2p3为x=p2.x()
```

```
                    //TODO:求(x3,y3)
```

```
                    x3 = p2.x();
```

```
                    y3 = k3*x3+b3;
```

```
                }
```

```
                else
```

```
                {
```

```
                    k4=(p3.y()-p2.y())/(p3.x()-p2.x());
```

```
                    b4 = p2.y()-k4*p2.x();
```

```
                    //TODO:求(x3,y3)
```

```
                    if(k3!=k4)
```

```
                    {
```

```
                        x3 = (b4-b3)/(k3-k4);
```

```
                        y3 = k3*x3+b3;
```

```
                    }
```

```
                }
```

```
            }
```

```
            pCross3= QPointF(x3,y3);
```

```
```

```
            //过pos做p2p3的垂线line5,line5方程为y=k5x+b5,line5与p2,p3交点为pCross5
```

```
            qreal k5,b5;
```

```
            qreal x5,y5;//pCross5(x5,y5),//y5=k5x5+b5,y5=k4x5+b4,求x5,y5
```

```
            if(p3.y()==p2.y())
```

```
            {
```

```
                //k3不存在,lin5为x=event->pos().x()
```

```
                //直线p2p3为y=k4x+b4
```

```
                if(p3.x()==p2.x())
```

```
                {
```

```
                    //k4不存在,直线p2p3为x=p2.x()
```

```
                    return;
```

```
                }
```

```
                else
```

```
                {
```

```
                    k4=(p3.y()-p2.y())/(p3.x()-p2.x());
```

```
                    b4 = p2.y()-k4*p2.x();
```

```
                    //TODO:求(x5,y5)
```

```
                    x5 = event->pos().x();
```

```
                    y5 = k4*x5+b4;
```

```
                }
```

```
            }
```

```
            else
```

```
            {
```

```
                k5 = (p2.x()-p3.x())/(p3.y()-p2.y());
```

```
                b5=event->pos().y()-k5*event->pos().x();
```

```
                //直线p2p3为y=k4x+b4
```

```
                if(p3.x()==p2.x())
```

```
                {
```

```
                    //k4不存在,直线p2p3为x=p2.x()
```

```
                    //TODO:求(x5,y5)
```

```
                    x5 = p2.x();
```

```
                    y5 = k5*x5+b5;
```

```
                }
```

```
                else
```

```
                {
```

```
                    k4=(p3.y()-p2.y())/(p3.x()-p2.x());
```

```
                    b4 = p2.y()-k4*p2.x();
```

```
                    //TODO:求(x5,y5)
```

```
                    if(k5!=k4)
```

```
                    {
```

```
                        x5 = (b4-b5)/(k5-k4);
```

```
                        y5 = k5*x5+b5;
```

```
                    }
```

```
                }
```

```
            }
```

```
            pCross5= QPointF(x5,y5);
```

```
```

```
            //求pos到垂线line3的距离为disShear
```

```
            double disShear = CalDisPoint2longLine(event->pos().x(),event->pos().y(),pc.x(),pc.y(),pCross3.x(),pCross3.y());
```

```
            double newHalfHeight;
```

```
            if(m_tCaliRect.m_bKeepShadowLength)
```

```
            {
```

```
                if(disShear>m_tCaliRect.m_RECT.height()/2-1)
```

```
                    disShear = m_tCaliRect.m_RECT.height()/2-1;
```

```
                newHalfHeight = sqrt(qPow(m_tCaliRect.m_RECT.height()/2,2)-disShear*disShear);
```

```
                m_tCaliRect.m_fShearX = disShear/newHalfHeight;
```

```
            }
```

```
            else
```

```
            {
```

```
                m_tCaliRect.m_fShearX = disShear/(m_tCaliRect.m_RECT.height()/2);
```

```
            }
```

```
            //确定往左斜切还是往右斜切
```

```
            if(((-90<m_tCaliRect.m_RotateAngle)&&(m_tCaliRect.m_RotateAngle<90))||(m_tCaliRect.m_RotateAngle>270 &&m_tCaliRect.m_RotateAngle<360)||m_tCaliRect.m_RotateAngle==360)
```

```
            {
```

```
                if(pCross5.x()<pCross3.x())
```

```
                    m_tCaliRect.m_fShearX = -m_tCaliRect.m_fShearX;
```

```
            }
```

```
            else if(m_tCaliRect.m_RotateAngle == 90)
```

```
            {
```

```
                if(pCross5.y()<pCross3.y())
```

```
                    m_tCaliRect.m_fShearX = -m_tCaliRect.m_fShearX;
```

```
            }
```

```
            else if(m_tCaliRect.m_RotateAngle>90&&m_tCaliRect.m_RotateAngle<270)
```

```
            {
```

```
                if(pCross5.x()>pCross3.x())
```

```
                    m_tCaliRect.m_fShearX = -m_tCaliRect.m_fShearX;
```

```
            }
```

```
            else if(m_tCaliRect.m_RotateAngle==270 ||m_tCaliRect.m_RotateAngle == -90)
```

```
            {
```

```
                if(pCross5.y()>pCross3.y())
```

```
                    m_tCaliRect.m_fShearX = -m_tCaliRect.m_fShearX;
```

```
            }
```

```
            if(m_tCaliRect.m_bKeepShadowLength)
```

```
            {
```

```
                setShearRectSize(QRectF(pc.x()-m_tCaliRect.m_RECT.width()/2,pc.y()-newHalfHeight,m_tCaliRect.m_newShearRECT.width(),newHalfHeight*2));//这个函数不会重置原始矩形的大小
```

```
            }
```

```
            else
```

```
            {
```

```
                setRectSize(m_tCaliRect.m_RECT);
```

```
            }
```

```
            scene()->update();
```

```
        }
```

```
        else if(m_StateFlag == CALI_RECT_BR)//右下角顶点
```

```
        {
```

```
            QPointF pc,p0,p1,p2,p3;//,pCross1,pCross2;
```

```
            pc = m_tCaliRect.m_RotateCenter;
```

```
            p0 = m_tCaliRect.m_RECT_Pol[0];
```

```
            p1 = m_tCaliRect.m_RECT_Pol[1];
```

```
            p2 = m_tCaliRect.m_RECT_Pol[2];
```

```
            p3 = m_tCaliRect.m_RECT_Pol[3];
```

```
            if(!get2CrossPt(p0,p1,p2,pc,event->pos(),pCross1,pCross2))
```

```
                return;
```

```
//            //该段代码可禁止矩形被反向拉伸!!!
```

```
//            double disVertical2RightLine = CalDisPoint2longLine(event->pos().x(),event->pos().y(),p1.x(),p1.y(),p2.x(),p2.y());
```

```
//            double disVertical2LeftLine = CalDisPoint2longLine(event->pos().x(),event->pos().y(),p0.x(),p0.y(),p3.x(),p3.y());
```

```
//            if(disVertical2RightLine>disVertical2LeftLine)
```

```
//                return;
```

```
//            double disVertical2BottomLine = CalDisPoint2longLine(event->pos().x(),event->pos().y(),p2.x(),p2.y(),p3.x(),p3.y());
```

```
//            double disVertical2TopLine = CalDisPoint2longLine(event->pos().x(),event->pos().y(),p0.x(),p0.y(),p1.x(),p1.y());
```

```
//            if(disVertical2BottomLine>disVertical2TopLine)
```

```
//                return;
```

```
//            //该段代码可禁止矩形被反向拉伸!!!
```

```
            if(m_tCaliRect.m_bKeepShadowLength && m_tCaliRect.m_fShearX!=0)//保证投影长度不变
```

```
            {
```

```
                double disp2pc = CalDis(m_tCaliRect.m_RECTShear[2].x(),m_tCaliRect.m_RECTShear[2].y(),pc.x(),pc.y());
```

```
                double dispospc = CalDis(event->pos().x(),event->pos().y(),pc.x(),pc.y());
```

```
                double newHeight = dispospc/disp2pc*m_tCaliRect.m_newShearRECT.height();
```

```
                double newWidth = dispospc/disp2pc*m_tCaliRect.m_newShearRECT.width();
```

```
                setShearRectSize(QRectF(pc.x()-newWidth/2,pc.y()-newHeight/2,newWidth,newHeight));
```

```
                double newHeightOld = dispospc/disp2pc*m_tCaliRect.m_RECT.height();
```

```
                double newWidthOld = dispospc/disp2pc*m_tCaliRect.m_RECT.width();
```

```
                m_tCaliRect.m_RECT = QRectF(pc.x()-newWidthOld/2,pc.y()-newHeightOld/2,newWidthOld,newHeightOld);
```

```
            }
```

```
            else//投影长度可变
```

```
            {
```

```
                //新矩形宽度一半:
```

```
                double dispcpCross1 = CalDis(pc.x(),pc.y(),pCross1.x(),pCross1.y());
```

```
                if(dispcpCross1<10)
```

```
                    return;//矩形宽度不能小于20
```

```
                //新矩形高度一半:
```

```
                double disVertical = CalDisPoint2longLine(event->pos().x(),event->pos().y(),pc.x(),pc.y(),pCross1.x(),pCross1.y());
```

```
                if(disVertical<10)
```

```
                    return;//矩形高度不能小于20
```

```
                setRectSize(QRectF(pc.x()-dispcpCross1,pc.y()-disVertical,dispcpCross1*2,disVertical*2));
```

```
```

```
            }
```

```
            scene()->update();
```

```
        }
```

```
    }
}