Qt图形视图框架---精确选中折线

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/u011680118/article/details/79886789

Qt的很多资料都可以参考这位博主:

https://blog.csdn.net/column/details/qshare.html?&page=2

项目中的折线都是先从一个点出发,纵向画一条线段,再画一条横线水平的线段,最后又画一条纵向的线段。

即 一纵线一横线一纵线 的特点。

连接两个设备端口的连接线如下图所示。



我设计的连接线类如下:

class GConnectLine : public QGraphicsPathItem
{
public:
    GConnectLine();  
    
    //判断点是否在连接线上
    bool containsPoint(const QPointF point);

    QPainterPath m_linePath;

    int m_rowLineX1;        //第1条纵线的横坐标
    int m_rowLineX2;        //第2条纵线的横坐标
    int m_StartPointY;      //起始点的纵坐标
    int m_EndPointY;        //终止点的纵坐标
    int m_rowLineY;         //中间横线的纵坐标,用于确定选中的哪条线

private:

    //折线polyline的属性部分
    QString m_d;            //各点的坐标(以空格分隔)
 
};

一、自定义折线选中样式

默认的选中样式是绘制boundingRect,也就是会把连接线的外围矩形(起始点为左上角,终止点为右下角的矩形)绘制一遍。

我参考了上述博客专栏中关于自定义QGraphicsItem选中样式的文章,写的很好

http://blog.csdn.net/liang19890820/article/details/53525478

在对连接线进行选中后,重写paint方法自定义选中样式,不绘制边框矩形,而是重新把连接线加粗、高亮黄色绘制一遍,达到高亮显示连接线的目的。


protected:
    void paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget = 0)
    {
        //连接线高亮 采用重绘连接线的方法 
            if (option->state & QStyle::State_Selected)
            {
                QGraphicsItem *item = childItems().at(0);
                GConnectLine *cl = (GConnectLine *)item;
                //用黄色更粗的线条绘制连接线,不再绘制boundingRect
                painter->setPen(QPen(QColor(Qt::yellow), 4, Qt::DashLine));
                painter->drawPath(cl->m_linePath);
            }  
    }

选中连接线后,高亮显示效果如下图。



二、精确选中折线

QGraphicsPathItem里面的boundingRect是从起始点到终止点的矩形,当设置连接线可以被选中后,鼠标单击boundingRect内任意点,都会被认为该连接线被选中了,这显然是不对的。

而且先画的连接线的boundingRect会被后画的连接线的boundingRect所覆盖,也就是如果我明明点击了某条线,但是由于它先加入QGraphicsScene,其boundingRect被后来的其他连接线所遮挡,结果会显示我点击了最上面一层的连接线,这也是不对的。


精确选中折线的思路为: 根据鼠标点击的点的坐标,判断这个点是否在某条连接线上,如果是,则设置这条连接线为选中状态。


为了实现精确选中连接线,我把所有连接线对象的引用保存在QList中。

重写QGraphicsView的鼠标单击事件 mousePressEvent(QMouseEvent *event)

在单击事件函数内,先获取鼠标单击点的场景坐标  QPointF point = mapToScene(event->pos());

再去所有连接线的QList中遍历,判断鼠标点击的是否是某条连接线。

下面是判断某个点是否在连接线上的代码:

//判断点是否在连接线上
bool GConnectLine::containsPoint(const QPointF point)
{
    int minDis = 1.2;
    //单击的点 落在横线上,纵坐标差距很小
    if((m_rowLineY - point.y() < minDis) && (point.y() - m_rowLineY < minDis)
    //单击的点 落在起始点出发的纵线上,纵坐标应该在起始点和第一个转折点的纵坐标范围内
       || (m_rowLineX1 - point.x() < minDis) && (point.x() - m_rowLineX1 < minDis)
       && ((m_StartPointY <= point.y()) && (m_rowLineY >= point.y())
           ||(m_StartPointY >= point.y()) && (m_rowLineY <= point.y()))
    //单击的点 落在到底终止点的纵线上,纵坐标应该在第二个转折点和终止点的纵坐标范围内
       || (m_rowLineX2 - point.x() < minDis) && (point.x() - m_rowLineX2 < minDis)
       && ((m_EndPointY >= point.y()) && (m_rowLineY <= point.y())
           ||(m_EndPointY <= point.y()) && (m_rowLineY >= point.y())))
    {
        return true;
    }
    else
        return false;
}

如果鼠标点击的是某条线,那么在鼠标单击事件函数中把该连接线设置为选中状态  setSelected(true)

也可以根据自己的线的特征来重写函数,判断某个点是否在线上。




猜你喜欢

转载自blog.csdn.net/u011680118/article/details/79886789
今日推荐