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();
最后实现效果: