QGraphicsItem封装的直线控件(添加箭头)

最近在封装QGraphicsScene的很多控件,需要在绘制直线后,显示箭头表示方向,并且该直线的起点和终点可变化(箭头需要实时变化)

    qreal alph = atan2(m_pointF2.y()-m_pointF1.y(), m_pointF2.x()-m_pointF1.x());
    painter->translate(m_pointF2);

    qreal angle = (alph*180)/3.14159;
    qDebug()<<angle;
    painter->rotate(angle);
    painter->drawLine(QPointF(-10,-5),QPointF(0,0));
    painter->drawLine(QPointF(-10,+5),QPointF(0,0));

在paint()函数中,进行重绘的封装的时候,添加代码。

在网上找的都是各种计算角度,其实将箭头所在的点作为画笔的起点,然后计算出直线的角度,再将画笔的角度设置为和直线的角度一致即可。
在这里插入图片描述

源码:
.cpp

#include "visionlineitem.h"
#include <QDebug>
#include <QPainterPath>

#include "../control/color.h"

VisionLineItem::VisionLineItem(bool bEdit, QPointF p1, QPointF p2, qreal penWidth, bool color_enable, QColor borderColor, QColor selectedColor, QColor brushColor, VisionItem *parent) : VisionItem(parent)
{
    if(color_enable){
        m_borderColor = borderColor;
    }else{
        m_borderColor = borderColor;
    }
    m_brushColor = brushColor;
    m_selectedColor = selectedColor;

    m_pointF1 = p1;m_pointF2 = p2;
    m_penColor = borderColor;
    m_penWidth = penWidth;
    m_bEdit = bEdit;
    m_type = ItemType::Paint_Line;

    if(m_bEdit){
        setSelectedStatus(true);
    }else{
        setSelectedStatus(false);
    }

    m_miniRect1 = new MiniRect(m_pointF1.x()-5,m_pointF1.y()-5,10,10,m_borderColor,m_selectedColor,m_brushColor,this);
//    m_miniRect1->setGlobleData(this->scene()->views().at(0)->matrix().m22(),g_penWidth);
    m_miniRect1->setIndex(1);
    connect(m_miniRect1,SIGNAL(signalIndex(int)),this,SLOT(slotMiniRectIndex(int)));
    m_miniRect1->hide();
    m_miniRect2 = new MiniRect(m_pointF2.x()-5,m_pointF2.y()-5,10,10,m_borderColor,m_selectedColor,m_brushColor,this);
//    m_miniRect2->setGlobleData(this->scene()->views().at(0)->matrix().m22(),g_penWidth);
    m_miniRect2->setIndex(2);
    connect(m_miniRect2,SIGNAL(signalIndex(int)),this,SLOT(slotMiniRectIndex(int)));
    m_miniRect2->hide();
    updateRect(m_pointF1,m_pointF2);
}

void VisionLineItem::setLine(QPointF p1, QPointF p2)
{
    m_pointF1 = p1;
    m_pointF2 = p2;
    m_miniRect1->setRect(m_pointF1.x()-5,m_pointF1.y()-5,10,10);
    m_miniRect2->setRect(m_pointF2.x()-5,m_pointF2.y()-5,10,10);

    updateRect(m_pointF1,m_pointF2);
}

void VisionLineItem::setPenWidth(qreal penWidth)
{
    m_penWidth = penWidth;
}

void VisionLineItem::setPenColor(QColor color)
{
    m_penColor = color;
}

bool VisionLineItem::getPosInArea(qreal x, qreal y)
{

    qreal A = m_pointF2.y() - m_pointF1.y();
    qreal B = m_pointF1.x() - m_pointF2.x();
    qreal C = m_pointF2.x()*m_pointF1.y() - m_pointF1.x()*m_pointF2.y();

    qreal l = fabs(A*x + B*y + C)/sqrt(A*A+B*B);
    if( l < 5 || this->cursor().shape() == Qt::SizeAllCursor){
        return true;
    }else{
        return false;
    }
}

QVector<QPointF> VisionLineItem::getPoints(){
    QVector<QPointF> vec_p;
    vec_p.append(m_pointF1);
    vec_p.append(m_pointF2);
    return vec_p;
}

QRectF VisionLineItem::boundingRect() const
{
    if(this->scene()->views().at(0)->matrix().m22() > 1){
        return QRectF(m_x-5*(1/this->scene()->views().at(0)->matrix().m22()),m_y-5*(1/this->scene()->views().at(0)->matrix().m22()),m_width+10*(1/this->scene()->views().at(0)->matrix().m22()),m_height+10*(1/this->scene()->views().at(0)->matrix().m22()));
    }else{
        return QRectF(m_x-5*(1/this->scene()->views().at(0)->matrix().m22()),m_y-5*(1/this->scene()->views().at(0)->matrix().m22()),m_width+10*(1/this->scene()->views().at(0)->matrix().m22()),m_height+10*(1/this->scene()->views().at(0)->matrix().m22()));
    }
}

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

    painter->setRenderHint(QPainter::Antialiasing, true);

    if(option->state & QStyle::State_Selected){
        painter->setPen(QPen(QBrush(m_selectedColor),g_penWidth*(1/this->scene()->views().at(0)->matrix().m22())));

    }else{
        painter->setPen(QPen(QBrush(m_borderColor),g_penWidth*(1/this->scene()->views().at(0)->matrix().m22())));

    }

    painter->drawLine(m_pointF1,m_pointF2);


    //绘制箭头
    qreal alph = atan2(m_pointF2.y()-m_pointF1.y(), m_pointF2.x()-m_pointF1.x());
    painter->translate(m_pointF2);

    qreal angle = (alph*180)/3.14159;
    qreal len = 5*(1/this->scene()->views().at(0)->matrix().m22());
//    qDebug()<<angle;
    painter->rotate(angle);
    painter->drawLine(QPointF(-(2*len),-len),QPointF(0,0));
    painter->drawLine(QPointF(-(2*len),+len),QPointF(0,0));

    if(!m_bEdit)
        return;

    //绘制编辑框
    if(option->state & QStyle::State_Selected){
        m_miniRect1->show();
        m_miniRect2->show();
        m_bSelected = true;
        setSelectedStatus(m_bSelected);
    }else{
        m_miniRect1->hide();
        m_miniRect2->hide();
        m_bSelected = false;
        setSelectedStatus(m_bSelected);
    }
}

void VisionLineItem::mousePressEvent(QGraphicsSceneMouseEvent *event)
{

    if(!m_bEdit)
        return;

    //            A = Y2 - Y1
    //            B = X1 - X2
    //            C = X2*Y1 - X1*Y2
    QGraphicsItem::mousePressEvent(event);

    if(m_iIndex != -1)
        return;

    qreal A = m_pointF2.y() - m_pointF1.y();
    qreal B = m_pointF1.x() - m_pointF2.x();
    qreal C = m_pointF2.x()*m_pointF1.y() - m_pointF1.x()*m_pointF2.y();
    m_lastPointF = event->scenePos();
    qreal l = fabs(A*event->scenePos().x() + B*event->scenePos().y() + C)/sqrt(A*A+B*B);

    qDebug()<<"l:: "<<l<<A<<B<<C;
    if(l < 5 || this->cursor().shape() == Qt::SizeAllCursor){
        qDebug()<<"in area";
        setSelectedStatus(true);
    }else{
        qDebug()<<"out area";
        setSelectedStatus(false);
    }
    this->scene()->update();
}

void VisionLineItem::mouseMoveEvent(QGraphicsSceneMouseEvent *event)
{
    if(!m_bEdit)
        return;

    if(!m_bSelected)
        return;

//    QGraphicsItem::mouseMoveEvent(event);
    QPointF disPointF = event->scenePos()-m_lastPointF;
    m_lastPointF = event->scenePos();
    if(m_iIndex == 1){
        m_pointF1 = event->scenePos();
    }else if(m_iIndex == 2){
        m_pointF2 = event->scenePos();
    }else{
        //移动整体
        m_pointF1 = m_pointF1 + disPointF;
        m_pointF2 = m_pointF2 + disPointF;
    }
    updateRect(m_pointF1,m_pointF2);
    emit signalChanged(this);
    this->scene()->update();
}

void VisionLineItem::mouseReleaseEvent(QGraphicsSceneMouseEvent *event)
{

    if(!m_bEdit)
        return;

    if(m_iIndex != -1)
        return;

    qreal A = m_pointF2.y() - m_pointF1.y();
    qreal B = m_pointF1.x() - m_pointF2.x();
    qreal C = m_pointF2.x()*m_pointF1.y() - m_pointF1.x()*m_pointF2.y();

    qreal l = fabs(A*event->scenePos().x() + B*event->scenePos().y() + C)/sqrt(A*A+B*B);
    if( l < 5 || this->cursor().shape() == Qt::SizeAllCursor){
        emit signal_clicked(this,true,true,event->scenePos().x(),event->scenePos().y());
        QGraphicsItem::mouseReleaseEvent(event);
    }else{
        emit signal_clicked(this,true,false,event->scenePos().x(),event->scenePos().y());
        return;
    }
}

void VisionLineItem::updateRect(QPointF p1, QPointF p2)
{
    if(p1.x() < p2.x()){
        m_x = p1.x();
    }else{
        m_x = p2.x();
    }

    if(p1.y() < p2.y()){
        m_y = p1.y();
    }else{
        m_y = p2.y();
    }
    m_width = fabs(p1.x()-p2.x());
    m_height = fabs(p1.y()-p2.y());

    m_miniRect1->setPos(m_pointF1.x()-5,m_pointF1.y()-5);
    m_miniRect2->setPos(m_pointF2.x()-5,m_pointF2.y()-5);

}

void VisionLineItem::slotMiniRectIndex(int index)
{
    if(index == 1){
        //移动点1
        m_iIndex = 1;
        this->scene()->views().at(0)->setCursor(Qt::SizeAllCursor);
    }else if(index == 2){
        //移动点2
        m_iIndex = 2;
        this->scene()->views().at(0)->setCursor(Qt::SizeAllCursor);
    }else{
        //恢复正常
        m_iIndex = -1;
        this->scene()->views().at(0)->setCursor(viewCursor);
    }
}

.h

/****************************************************************************
** @brief       line类
** @note        可编辑的line,绘制完成后,可修改线的起点和终点,带有箭头的表示方向,默认起点指向终点
** @date        create:2018-09-28
** @example
****************************************************************************/


#ifndef VISIONLINEITEM_H
#define VISIONLINEITEM_H

#include <QObject>
#include <QPainter>
#include "../control/visionitem.h"
#include "../control/minirect.h"

class VISIONGRAPHSHARED_EXPORT VisionLineItem : public VisionItem
{
    Q_OBJECT
public:

    /**
     * @brief       构造函数
     * @param       对line的一些属性进行设置
     * @param       p1 p2 起点和终点 bEdit控制该line是否是可编辑的(起点终点可更改),penWidth penColor画笔的属性
     */
    explicit VisionLineItem(bool bEdit = true, QPointF p1 = QPointF(0,0), QPointF p2 = QPointF(0,0), qreal penWidth = 0,
                            bool color_enable = false,
                            QColor borderColor = QColor(255,0,0),QColor selectedColor = QColor(255,0,0),QColor brushColor = QColor(255,0,0,160),
                            VisionItem *parent = 0);

    /**
     * @brief       设置线的起点和终点
     * @param       p1 p2 起点和终点
     */
    void setLine(QPointF p1,QPointF p2);

    /**
     * @brief       设置画笔宽度
     */
    void setPenWidth(qreal penWidth);

    /**
     * @brief       设置画笔颜色
     */
    void setPenColor(QColor color);

    /**
     * @brief       判断点(x,y)是否在该item内
     * @param       bool
     */
    bool getPosInArea(qreal x, qreal y);

    /**
     * @brief       获取Line的P1
     * @param       QpointF
     */
    QPointF getP1(){
        return m_pointF1;
    }

    /**
     * @brief       获取Line的P2
     * @param       QpointF
     */
    QPointF getP2(){
        return m_pointF2;
    }

    /**
     * @brief       获取每个顶点
     * @param       point vec
     */
    QVector<QPointF> getPoints();

    VGSegment2D getData(){
        VGSegment2D segment2D;
        segment2D.optional = VG_ENABLE;
        VGPoint2D p1,p2;
        p1.x = m_pointF1.x();
        p1.y = m_pointF1.y();
        p2.x = m_pointF2.x();
        p2.y = m_pointF2.y();
        segment2D.point1 = p1;
        segment2D.point2 = p2;
        return segment2D;
    }

protected:
    QRectF boundingRect() const;
    void paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget);
    void mousePressEvent(QGraphicsSceneMouseEvent *event);
    void mouseMoveEvent(QGraphicsSceneMouseEvent *event);
    void mouseReleaseEvent(QGraphicsSceneMouseEvent *event);

signals:
    void signalChanged(VisionItem* item);

private:
    qreal m_x=0;qreal m_y;qreal m_width=0;qreal m_height=0;
    QPointF m_pointF1 = QPointF(0,0);
    QPointF m_pointF2 = QPointF(0,0);
    qreal m_penWidth = 0;
    QColor m_penColor = QColor(0,0,0);

    int m_iIndex = -1;
    MiniRect* m_miniRect1 = nullptr;
    MiniRect* m_miniRect2 = nullptr;

    qreal m_angle = 0;  //角度
    QPointF m_lastPointF;

    QColor m_borderColor;
    QColor m_brushColor;
    QColor m_selectedColor;

private:

    /**
     * @brief       miniRect的刷新---主要是调整位置
     * @param       编辑模式下,会更改miniRect的位置---miniRect跟随line的起点和终点变化而变化
     */
    void updateRect(QPointF p1,QPointF p2);

private slots:

    /**
     * @brief       控制miniRect的下标
     * @param       编辑模式下,确认鼠标所控制的miniRect的下标
     */
    void slotMiniRectIndex(int index);

public slots:
};

#endif // VISIONLINEITEM_H

评论 18
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

庐州李大爷

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

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

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

打赏作者

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

抵扣说明:

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

余额充值