qt中實現qchart的圖例點擊操作功能

qt自從提供了qchart之後,可以製作很多圖表展示界面,但是qchart的功能有時和實際需求不一樣。對於用慣了highcharts的人來說,不能通過圖例實現對qchart的操作,感覺很彆扭。所以我只好自己開發一個。

具體實現有兩個類:TringleLegend和LegendManager,TringleLegend負責畫圖例和感知點擊事件,LegendManager負責管理圖例。

TringleLegend的定義:tringlelegend.h

#include <QtCharts/QChartGlobal>
#include <QtWidgets/QGraphicsItem>
#include <QtGui/QFont>
#include <QChart>
#include <QEvent>

QT_BEGIN_NAMESPACE
class QGraphicsSceneMouseEvent;
QT_END_NAMESPACE

QT_CHARTS_BEGIN_NAMESPACE
class QChart;
QT_CHARTS_END_NAMESPACE

QT_CHARTS_USE_NAMESPACE

//因爲要使用信號槽機制,所以要繼承QObject
class TriggerLegend : public QObject, public QGraphicsItem
{
    Q_OBJECT
public:
    explicit TriggerLegend(QChart *parent);
    virtual ~TriggerLegend(){}

    //圖例圖標的顏色
    void setEllipseColor(const QColor &color);
    QColor getEllipseColor();

    //設置圖例的文字
    void setText(const QString& text);
    QString getText();

    //設置錨點
    void setAnchor(QPointF point);

    //給圖例定義序號
    void setIndex( int idx );
    int getIndex();

    //圖例是否處在激活狀態
    bool isActived(){return m_bActived;}

    //更新外形結構
    void updateGeometry();

    //獲取邊框
    QRectF boundingRect() const;
    void paint(QPainter *painter, const QStyleOptionGraphicsItem *option,QWidget *widget);
signals:
    //點擊信號
    void clicked();
protected:
    void mousePressEvent(QGraphicsSceneMouseEvent *event);
    void hoverEnterEvent(QGraphicsSceneHoverEvent *event);
    void hoverLeaveEvent(QGraphicsSceneHoverEvent *event);

private:
    QString m_text;
    QRectF m_textRect;
    QRectF m_rect;
    QPointF m_anchor;
    QFont m_font;
    QChart *m_chart;
    QColor m_ellipseColor;
    bool m_bActived;
    int m_index;
};

tringlelegend.cpp

#include "triggerlegend.h"


#include <QPainter>
#include <QDebug>
#include <QGraphicsSceneMouseEvent>
#include <QGraphicsSceneHoverEvent>


/**
 * legend組成 shape(10,10)+text(length,10);
 * m_rect width:5+shape.width+10+text.length+5, height:20
 */



TriggerLegend::TriggerLegend(QChart *parent )
    :QGraphicsItem(parent),
    m_chart(parent),
    m_bActived(true),
    m_index(0)
{
}


QRectF TriggerLegend::boundingRect() const
{
    return m_rect;
}

void TriggerLegend::paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget)
{
    Q_UNUSED(option)
    Q_UNUSED(widget)
    QRectF boundRect = m_chart->boundingRect();
    //
    QPen pen = painter->pen();
    pen.setWidth(2);
    pen.setColor(QColor(205,205,205));
    painter->setPen(pen);
    QColor shapeColor(205,205,205);
    QColor textColor(205,205,205);
    if( m_bActived )
    {
        shapeColor = m_ellipseColor;
        textColor = QColor(0,0,0);
    }
    painter->setBrush(shapeColor);
    QRectF rect(boundRect.x()/2+5, 10, 10, 10 );
    m_textRect.setLeft(boundRect.x()/2+30);
    painter->drawRect(rect);
    pen = painter->pen();
    pen.setColor(textColor);
    painter->setPen(pen);
    painter->drawText(m_textRect, m_text);
//    qDebug() << this->boundingRect() << m_textRect;
//    painter->drawRect(this->boundingRect());
}

void TriggerLegend::setEllipseColor(const QColor& color)
{
    m_ellipseColor = color;
    show();
}
QColor TriggerLegend::getEllipseColor()
{
    return m_ellipseColor;
}

void TriggerLegend::setText(const QString& text)
{
    m_text = text;
    QFontMetrics metrics(m_font);
    m_textRect = metrics.boundingRect(QRect(20, 5, 200, 150), Qt::AlignLeft, m_text);
    m_textRect.translate(10, 5);

    prepareGeometryChange();
    m_rect = m_textRect.adjusted(-25, -5, 5, 5);
//    qDebug() << "TriggerLegend m_rect:" << m_rect;
//    this->boundingRect()
}


QString TriggerLegend::getText()
{
    return m_text;
}

void TriggerLegend::setAnchor(QPointF point)
{
    m_anchor = point;
}

void TriggerLegend::setIndex( int idx )
{
    m_index = idx;
}

int TriggerLegend::getIndex()
{
    return m_index;
}

void TriggerLegend::updateGeometry()
{
    prepareGeometryChange();
    setPos(m_anchor + QPoint(0, 0));
//    qDebug() << m_anchor;
}


void TriggerLegend::mousePressEvent(QGraphicsSceneMouseEvent *event)
{
    if( m_bActived )
    {
        m_bActived = false;
    }
    else
    {
        m_bActived = true;
    }
//    qDebug() << this->m_text;
    updateGeometry();
    emit clicked();
    event->setAccepted(true);
}

void TriggerLegend::hoverEnterEvent(QGraphicsSceneHoverEvent *event)
{
//    qDebug() << this->m_text;
    event->setAccepted(true);
}
void TriggerLegend::hoverLeaveEvent(QGraphicsSceneHoverEvent *event)
{
    event->setAccepted(true);
}

LegendManager的定義:legendManager.h

#include "triggerlegend.h"


class LegendManager : public QObject
{
    Q_OBJECT
public:
    explicit LegendManager(QChart *chart);
    ~LegendManager();

    void InitLegends();
    void FreshLegends();
    void ClearLegends();
public slots:
    void legendClick();

private:
    QChart* m_chart;
    QVector<TriggerLegend*> m_vLegend;
};

LegendManager的實現,legendManager.cpp

#include "legendmanager.h"

#include <QLineSeries>

LegendManager::LegendManager(QChart *chart)
    :m_chart(chart)
{

}

LegendManager::~LegendManager()
{

}


void LegendManager::InitLegends()
{
    for( TriggerLegend* pLegend : m_vLegend )
    {
        pLegend->hide();
        delete pLegend;
    }

    m_vLegend.clear();
    for( int i = 0; i < m_chart->series().size(); ++i )
    {
        const QXYSeries* pSeries = dynamic_cast<QXYSeries*>(m_chart->series().at(i));
        if(pSeries == nullptr )
            continue;

        TriggerLegend *lgd = new TriggerLegend(m_chart);
        lgd->setEllipseColor(pSeries->color());
        if( pSeries->name().isEmpty() )
        {
            lgd->setText(QString("series%1").arg(i));
        }
        else
        {
            lgd->setText(pSeries->name());
        }
        lgd->setZValue(11);
//        qDebug() << "lgd->boundingRect():" << lgd->boundingRect() << pSeries->name();
//        sumWidth += lgd->boundingRect().width();
//        sumHeight = lgd->boundingRect().height();
        connect(lgd,SIGNAL(clicked()),this,SLOT(legendClick()));
        m_vLegend.append(lgd);
    }

    FreshLegends();
}

void LegendManager::FreshLegends()
{
    double rectWidth = m_chart->boundingRect().width();
    double rectHeight = m_chart->boundingRect().height();
    double width;
    double height;
    double left = 0;
//    qDebug() << "m_chart->boundingRect: " << m_chart->boundingRect();
    double sumWidth = 0;//, sumHeight = 0;
    for( TriggerLegend *pLegend : m_vLegend )
    {
        sumWidth += pLegend->boundingRect().width();
    }
    for( TriggerLegend *pLegend : m_vLegend )
    {
        width = pLegend->boundingRect().width();
        height = pLegend->boundingRect().height();
        pLegend->setAnchor(QPointF( (rectWidth-sumWidth)/2 + left,
                                     (rectHeight-height)-10));

        pLegend->updateGeometry();
        pLegend->show();
        left += width + 10;
    }
}


void LegendManager::ClearLegends()
{
    m_vLegend.clear();
}


void LegendManager::legendClick()
{
    TriggerLegend* pLegend = dynamic_cast<TriggerLegend*>(sender());
    int seriesIndex = m_vLegend.indexOf(pLegend);
    if( seriesIndex >= 0 && seriesIndex < m_chart->series().size() )
    {
        if( pLegend->isActived() )
        {
            m_chart->series()[seriesIndex]->show();
        }
        else
        {
            m_chart->series()[seriesIndex]->hide();
        }
    }
}

調用legendManager:

    //m_chart爲定義的QChart*
    if( m_pLegendManager == nullptr )
    {
        m_pLegendManager = new LegendManager(m_chart);
    }
    m_pLegendManager->InitLegends();

最後實現效果:

效果圖

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章