QGraphisView编写箭头与圆指向关系

效果图
在这里插入图片描述
QWHArrowItem类头文件

#ifndef QWHARROWITEM_H
#define QWHARROWITEM_H

#include <QGraphicsLineItem>
#include "qwhcircleitem.h"

class QWHArrowItem : public QGraphicsLineItem
{
public:
    enum {Type = UserType};
    explicit QWHArrowItem(QWHCircleItem *startItem, QWHCircleItem *endItem, QGraphicsItem *parent = nullptr);
    ~QWHArrowItem();

    int type() const override;
    QRectF boundingRect() const override;
    QPainterPath shape() const override;

protected:
    void paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget = nullptr) override;

public:
    //位置更新
    void updatePosition();
    //获取起始Item
    QWHCircleItem *getStartItem();
    //获取结束Item
    QWHCircleItem *getEndItem();

private:
    QWHCircleItem *m_startItem; //起始Item
    QWHCircleItem *m_endItem;   //结束Item
    qreal m_arrowSize;          //箭头大小

    QColor m_lineColor;         //线条颜色
    QColor m_arrowColor;        //箭头颜色
};

#endif // QWHARROWITEM_H

QWHArrowItem类的核心代码

void QWHArrowItem::paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget)
{
    Q_UNUSED(option)
    Q_UNUSED(widget)

    //碰撞时不绘制箭头
    if (m_startItem->collidesWithItem(m_endItem))
        return;

    //半径
    int startItemRadius = m_startItem->radius();
    int endItemRadius = m_endItem->radius();
    //绘制箭头
    double radians = qAcos(line().dx() / line().length());
    if (line().dy() > 0)
    {//得到真正的弧度,qAcos函数返回的弧度在0-M_PI之间
        radians = 2 * M_PI - radians;
    }
    radians += M_PI;
    //获取圆和直线的交点,箭头绘制在交点处,不绘制在圆心(直线末端)
    QPointF startPoint = line().p1() + QPointF(startItemRadius * qCos(radians + M_PI), -startItemRadius * qSin(radians + M_PI));
    QPointF endPoint = line().p2() + QPointF(endItemRadius * qCos(radians), -endItemRadius * qSin(radians));

    double radiusL = radians - qDegreesToRadians(30.0); //箭头左边线段,角度可变
    double radiusR = radians + qDegreesToRadians(30.0); //箭头右边线段,角度可变
    QPointF pointL = QPointF(endPoint.x() + m_arrowSize * qCos(radiusL), endPoint.y() - m_arrowSize * qSin(radiusL));
    QPointF pointR = QPointF(endPoint.x() + m_arrowSize * qCos(radiusR), endPoint.y() - m_arrowSize * qSin(radiusR));
    QLineF lineL = QLineF(endPoint, pointL);
    QLineF lineR = QLineF(endPoint, pointR);

    painter->setPen(QPen(m_lineColor, 2, Qt::SolidLine, Qt::RoundCap, Qt::RoundJoin));
    painter->drawLine(startPoint, endPoint);

    QPainterPath path;
    path.moveTo(endPoint);
    path.lineTo(pointL);
    path.lineTo(pointR);
    painter->fillPath(path, m_arrowColor);
}

QWHCircleItem头文件

#ifndef QWHCIRCLEITEM_H
#define QWHCIRCLEITEM_H

#include <QGraphicsEllipseItem>
class QWHArrowItem;

class QWHCircleItem : public QGraphicsEllipseItem
{
public:
    enum {Type = UserType + 2};
    explicit QWHCircleItem(QPointF pos, qreal radius, QGraphicsItem *parent = nullptr);
    ~QWHCircleItem();

    int type() const override;

public:
    //添加箭头
    void addArrow(QWHArrowItem *arrow);
    //移除箭头
    void removeArrow(QWHArrowItem *arrow);
    //移出所有箭头
    void removeArrows();
    //获取半径
    qreal radius();

protected:
    //位置改变
    QVariant itemChange(QGraphicsItem::GraphicsItemChange change, const QVariant &value) override;

private:
    QList<QWHArrowItem *> m_arrows; //箭头集合
    qreal m_radius;                 //半径
};

#endif // QWHCIRCLEITEM_H

QWHCircleItem类的核心代码

void QWHCircleItem::removeArrows()
{
    foreach (QWHArrowItem *arrow, m_arrows)
    {
        arrow->getStartItem()->removeArrow(arrow);
        arrow->getEndItem()->removeArrow(arrow);
        scene()->removeItem(arrow);
        delete arrow;
    }
}

QVariant QWHCircleItem::itemChange(QGraphicsItem::GraphicsItemChange change, const QVariant &value)
{
    if (change == ItemPositionChange && scene())
    {
        foreach (QWHArrowItem *arrow, m_arrows)
            arrow->updatePosition();
    }

    return value;
}
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

浮生卍流年

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值