#include "WindowAppItemLinkLine.h" #include "WindowAppItemLink.h" WindowAppItemLinkLine::WindowAppItemLinkLine( QPointF ptStart, QPointF ptEnd, QGraphicsItemGroup* parent, LINK_MODE linkMode ) : m_bLinkEndLine(false) , m_bLinkStartLine(false) , m_bIsDragging(false) , m_mode(linkMode) , m_nLineIndex(-1) { // 接收悬停事件,用于显示鼠标切换效果 setAcceptHoverEvents(true); // 设置风格,可选择可拖动 // setFlag(QGraphicsItem::ItemIsMovable, true); setFlag(QGraphicsItem::ItemIsSelectable, true); // 接收Item移动消息 // setFlag(QGraphicsItem::ItemSendsGeometryChanges); this->setParentItem(parent); m_parentGroup = qgraphicsitem_cast(parent); this->setLine(QLineF(ptStart, ptEnd)); // 设置画笔 setPen(QPen(COLOR_INF_LINE, PEN_LINE_WIDTH, Qt::SolidLine, Qt::RoundCap, Qt::RoundJoin)); } /// /// 更新连线位置 /// /// /// void WindowAppItemLinkLine::updateLine(QPointF ptStart, QPointF ptEnd) { this->setLine(QLineF(ptStart, ptEnd)); } /// /// 更新线段的起点坐标 /// /// void WindowAppItemLinkLine::setP1(const QPointF pt) { QLineF ajustLine = this->line(); ajustLine.setP1(pt); this->setLine(ajustLine); } /// /// 更新线段的终点坐标 /// /// void WindowAppItemLinkLine::setP2(const QPointF pt) { QLineF ajustLine = this->line(); ajustLine.setP2(pt); this->setLine(ajustLine); } /// /// 返回边界区域 /// /// QRectF WindowAppItemLinkLine::boundingRect() const { qreal extra = (pen().width()) * 4.0; QRectF rc = QRectF( line().p1(), QSizeF(line().p2().x() - line().p1().x(), line().p2().y() - line().p1().y() )) .normalized() .adjusted(-extra, -extra, extra, extra); return rc; } /// /// 形状边界(为了扩大线条的可点击范围) /// /// QPainterPath WindowAppItemLinkLine::shape() const { QPainterPath path = QGraphicsLineItem::shape(); qreal extra = (pen().width()) * 4.0; extra *= 1.414; path = QGraphicsLineItem::shape(); // 通过Stroker设置精确Shape QPainterPathStroker stroker; stroker.setWidth(extra); path = stroker.createStroke(path); return path; } /// /// 绘制线条 /// /// /// /// void WindowAppItemLinkLine::paint(QPainter* painter, const QStyleOptionGraphicsItem* option, QWidget* widget /*= nullptr*/) { Q_UNUSED(option); Q_UNUSED(widget); painter->setRenderHint(QPainter::Antialiasing, true); painter->save(); // 如果父类的选中状态发生了变更的话 if (this->parentItem()->isSelected()) { painter->setPen(QPen(COLOR_INF_LINE, PEN_LINE_WIDTH_SEL, Qt::SolidLine, Qt::RoundCap, Qt::RoundJoin)); } else { painter->setPen(QPen(COLOR_INF_LINE, PEN_LINE_WIDTH, Qt::SolidLine, Qt::RoundCap, Qt::RoundJoin)); } // 绘制线条 painter->drawLine(line()); // 如果是终点连接线,需要绘制箭头 if (this->m_bLinkEndLine) { double angle = atan2(line().dy(), -line().dx()); QPointF arrowP1 = line().p2() + QPointF(sin(angle + M_PI / 3) * LINE_ARROW_SIZE, cos(angle + M_PI / 3) * LINE_ARROW_SIZE); QPointF arrowP2 = line().p2() + QPointF(sin(angle + M_PI - M_PI / 3) * LINE_ARROW_SIZE, cos(angle + M_PI - M_PI / 3) * LINE_ARROW_SIZE); painter->drawLine(line().p2(), arrowP1); painter->drawLine(line().p2(), arrowP2); } painter->restore(); } /// /// 跳过Group,自行处理部分消息 /// /// /// bool WindowAppItemLinkLine::sceneEvent(QEvent* event) { switch (event->type()) { // 处理鼠标Hover消息,很奇怪不知道为什么在Group中无法触发这个消息,只能放到子线段中了 case QEvent::GraphicsSceneHoverEnter: hoverEnterEvent(static_cast(event)); break; case QEvent::GraphicsSceneMousePress: mousePressEvent(static_cast(event)); break; case QEvent::GraphicsSceneMouseMove: mouseMoveEvent(static_cast(event)); break; case QEvent::GraphicsSceneMouseRelease: mouseReleaseEvent(static_cast(event)); break; } event->accept(); return QGraphicsLineItem::sceneEvent(event); } ///// ///// 鼠标悬浮事件(用于显示移动用的鼠标) ///// ///// //void WindowAppItemLinkLine::hoverMoveEvent(QGraphicsSceneHoverEvent* event) //{ // // 如果控件处于选中状态,则根据鼠标位置显示拉伸鼠标 // if (this->isSelected()) // { // //setCursor(Qt::SizeVerCursor); // // setCursor(Qt::SizeHorCursor); // } // // qDebug() << "WindowAppItemLinkLine::hoverMoveEvent"; // // QGraphicsLineItem::hoverMoveEvent(event); //} //============================================================================= // // 线条拖动相关代码 // //============================================================================= /// /// 鼠标进入悬浮事件(用于显示拖动用的鼠标) /// /// void WindowAppItemLinkLine::hoverEnterEvent(QGraphicsSceneHoverEvent* event) { // qDebug() << "WindowAppItemLinkLine::hoverEnterEvent"; // 如果不支持拖拽,则干脆不能改变鼠标样式 if (!isSupportDrag()) { return; } // 根据是水平线还是垂直线显示不同的鼠标 if (isVertical()) { setCursor(Qt::SizeHorCursor); } else if(isHorizontal()) { setCursor(Qt::SizeVerCursor); } // Error else { } QGraphicsLineItem::hoverEnterEvent(event); } /// /// 鼠标按下事件(用于触发Link移动) /// /// void WindowAppItemLinkLine::mousePressEvent(QGraphicsSceneMouseEvent* event) { // qDebug() << "WindowAppItemLinkLine::mousePressEvent"; // QPointF mousePoint = event->pos(); if (!this->isSupportDrag()) { return; } m_bIsDragging = true; QGraphicsLineItem::mousePressEvent(event); } /// /// 鼠标移动事件(用于移动Link) /// /// void WindowAppItemLinkLine::mouseMoveEvent(QGraphicsSceneMouseEvent* event) { // qDebug() << "WindowAppItemLinkLine::mouseMoveEvent"; QPointF mousePoint = event->pos(); if (!m_bIsDragging) { return; } QPointF lineP1 = this->line().p1(); QPointF lineP2 = this->line().p2(); // 水平线移动 if (isVertical()) { lineP1.setX(mousePoint.x()); lineP2.setX(mousePoint.x()); // 交给Group检查一下本次移动是否可行 if (m_parentGroup->canMove(lineP1, lineP2)) { this->setLine(QLineF(lineP1, lineP2)); // 发送线段移动信号,用于在Group中同步移动其他线段 emit lineMoveSignal(this); } } // 垂直线移动 else if(isHorizontal()) { lineP1.setY(mousePoint.y()); lineP2.setY(mousePoint.y()); // 交给Group检查一下本次移动是否可行 if (m_parentGroup->canMove(lineP1, lineP2)) { this->setLine(QLineF(lineP1, lineP2)); // 发送线段移动信号,用于在Group中同步移动其他线段 emit lineMoveSignal(this); } } // Error else { } QGraphicsLineItem::mouseMoveEvent(event); } /// /// 鼠标释放事件(用于鼠标还原以及接收拉伸状态) /// /// void WindowAppItemLinkLine::mouseReleaseEvent(QGraphicsSceneMouseEvent* event) { // qDebug() << "WindowAppItemLinkLine::mouseReleaseEvent"; // 还原鼠标 // setCursor(Qt::ArrowCursor); m_bIsDragging = false; QGraphicsLineItem::mouseReleaseEvent(event); } /// /// 是否是垂直线条 /// /// bool WindowAppItemLinkLine::isVertical() { QLine seg = this->line().toLine(); return (seg.x1() == seg.x2()); } /// /// 是否是水平线条 /// /// bool WindowAppItemLinkLine::isHorizontal() { QLine seg = this->line().toLine(); return (seg.y1() == seg.y2()); } /// /// 本线段是否支持拖拽 /// /// bool WindowAppItemLinkLine::isSupportDrag() { // 如果终点连线,则不支持拖拽功能 if (m_bLinkEndLine) { return false; } // 如果是普通模式下的起点连线,也不支持拖拽功能 if (m_bLinkStartLine && m_mode == LINK_MODE::LINK_NORMAL) { return false; } return true; }