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)
也可以根据自己的线的特征来重写函数,判断某个点是否在线上。