代码:可以在QT5.9的example中的barchart直接修改。
思路:继承QGraphicsItem和QGraphicsLayoutItem,将marker和label作为图例的最小单位设计出LegendItem;然后用QGraphicsGridLayout为LegendItem进行分行分列排版,添加至QGraphicsWidget的layout中;最后将QGraphicsWidget作为图形item加入到QChart的scence中,并设置原来的legend不可见。
不可行的方法:如果直接用api(chart->legend()->setLayout(QGraphicsGridLayout))会出现崩溃,具体原因我没有深究,毕竟代码是半年前写的。
后续优化:因为涉及到了LegendItem的排版,所以最好还是自定义一个QChartView,方便重写一些resize事件。
图例:customlegend.h
#ifndef CUSTOMLEGEND_H
#define CUSTOMLEGEND_H
#include <QGraphicsLayoutItem>
#include <QGraphicsItem>
#include <QChartView>
#include <QChart>
#include <QBarSet>
#include <QBarSeries>
QT_CHARTS_USE_NAMESPACE
class LegendItem : public QGraphicsLayoutItem, public QGraphicsItem
{
public:
LegendItem(QChart *pChart, QGraphicsLayoutItem *pLayout = nullptr, QGraphicsItem *parent = nullptr);
~LegendItem();
// Inherited from QGraphicsLayoutItem
QSizeF sizeHint(Qt::SizeHint which, const QSizeF &constraint = QSizeF()) const override;
void setLegendItem(QString sTmp, QColor color, int nIndex, QBarSet *pBar, QBarSeries *pSeries);
// Inherited from QGraphicsItem
QRectF boundingRect() const override;
void updateGeometry();
void setGeometry(const QRectF &geom) override;
void paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget = 0) override;
protected:
void mousePressEvent(QGraphicsSceneMouseEvent *event);
// void hoverEnterEvent(QGraphicsSceneMouseEvent *event);
/* void mouseReleaseEvent(QGraphicsSceneMouseEvent *event);*/
private:
QString m_sLabel;
QColor m_color;
int m_nLine;
QChart *m_pChart;
int m_nBarSetIndex;
QList<QBarSet*> m_lstBarSet;
QBarSet *m_pBarSet;
QBarSeries *m_pBarSeries;
QObject m_object;
};
#endif
customlegend.cpp
#include "customlegend.h"
#include <QGraphicsSceneResizeEvent>
#include <QGraphicsLayout>
#include <QPainter>
#include <QAbstractSeries>
#include <QDebug>
LegendItem::LegendItem(QChart *pChart, QGraphicsLayoutItem *playout, QGraphicsItem *parent)
:m_pChart(pChart), QGraphicsLayoutItem(playout), QGraphicsItem(parent)
{
setGraphicsItem(this);
setZValue(20);
setAcceptedMouseButtons(Qt::LeftButton);
setMaximumWidth(1000);
m_pBarSeries = NULL;
m_pBarSet = NULL;
}
LegendItem::~LegendItem()
{
}
QSizeF LegendItem::sizeHint(Qt::SizeHint which, const QSizeF &constraint) const
{
QGraphicsTextItem item(m_sLabel);
double nWidth = item.boundingRect().width();
double nHeight = item.boundingRect().height();
return QSizeF(nWidth + nHeight, nHeight);
}
void LegendItem::setLegendItem(QString sTmp, QColor color, int nIndex, QBarSet *pBar, QBarSeries *pSeries)
{
m_sLabel = sTmp;
m_color = color;
m_nBarSetIndex = nIndex;
m_pBarSet = pBar;
m_pBarSeries = pSeries;
prepareGeometryChange();
}
QRectF LegendItem::boundingRect() const
{
QGraphicsTextItem item(m_sLabel);
double nWidth = item.boundingRect().width();
double nHeight = item.boundingRect().height();
qreal nShift = m_pChart->boundingRect().width() - m_pChart->legend()->layout()->contentsRect().width();
return QRectF(QPointF(0, 0), QSizeF(nWidth + nHeight, nHeight));
}
void LegendItem::updateGeometry()
{
prepareGeometryChange();
}
void LegendItem::setGeometry(const QRectF &geom)
{
prepareGeometryChange();
QGraphicsLayoutItem::setGeometry(geom);
// qDebug() << geom;
setPos(geom.topLeft());
}
void LegendItem::paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget /*= 0*/)
{
Q_UNUSED(widget);
Q_UNUSED(option);
QRectF rect = boundingRect();
double nHeight = rect.height();
painter->setRenderHint(QPainter::Antialiasing);
painter->setPen(Qt::NoPen);
painter->setBrush(m_color);
//painter->drawRoundRect(rect.topLeft().x(), rect.topLeft().y(), nHeight, nHeight);
painter->drawEllipse(rect.topLeft() + QPointF(nHeight / 2, nHeight / 2), nHeight / 2, nHeight / 2);
painter->setPen(Qt::black);
painter->drawText(rect.adjusted(nHeight, 0, 0, 0), Qt::AlignCenter, m_sLabel);
}
void LegendItem::mousePressEvent(QGraphicsSceneMouseEvent *event)
{
event->setAccepted(true);
if (this->contains(event->pos()))
{
//qDebug() << event->pos() << m_pChart->mapToPosition(this->pos());
}
if (!m_pBarSeries || !m_pBarSet)
{
return;
}
QList<QBarSet *> lstBar = m_pBarSeries->barSets();
if (lstBar.contains(m_pBarSet))
{
qDebug() << m_pBarSeries->children().size() << m_pBarSet->label();
m_pBarSeries->take(m_pBarSet);
m_color.setAlphaF(0.5);
}
else
{
m_pBarSeries->insert(m_nBarSetIndex, m_pBarSet);
m_color.setAlphaF(1);
}
this->updateGeometry();
}
main.cpp
/****************************************************************************
**
** Copyright (C) 2016 The Qt Company Ltd.
** Contact: https://www.qt.io/licensing/
**
** This file is part of the Qt Charts module of the Qt Toolkit.
**
** $QT_BEGIN_LICENSE:GPL$
** Commercial License Usage
** Licensees holding valid commercial Qt licenses may use this file in
** accordance with the commercial license agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
** a written agreement between you and The Qt Company. For licensing terms
** and conditions see https://www.qt.io/terms-conditions. For further
** information use the contact form at https://www.qt.io/contact-us.
**
** GNU General Public License Usage
** Alternatively, this file may be used under the terms of the GNU
** General Public License version 3 or (at your option) any later version
** approved by the KDE Free Qt Foundation. The licenses are as published by
** the Free Software Foundation and appearing in the file LICENSE.GPL3
** included in the packaging of this file. Please review the following
** information to ensure the GNU General Public License requirements will
** be met: https://www.gnu.org/licenses/gpl-3.0.html.
**
** $QT_END_LICENSE$
**
****************************************************************************/
#include <QtWidgets/QApplication>
#include <QtWidgets/QMainWindow>
#include <QtCharts/QChartView>
#include <QtCharts/QBarSeries>
#include <QtCharts/QBarSet>
#include <QtCharts/QLegend>
#include <QtCharts/QBarCategoryAxis>
#include <QGraphicsGridLayout>
#include <QDebug>
#include "customlegend.h"
QT_CHARTS_USE_NAMESPACE
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
//![1]
QBarSet *set0 = new QBarSet("Jane");
QBarSet *set1 = new QBarSet("John");
QBarSet *set2 = new QBarSet("Axel");
QBarSet *set3 = new QBarSet("Mary");
QBarSet *set4 = new QBarSet("Samantha");
*set0 << 1 << 2 << 3 << 4 << 5 << 6;
*set1 << 5 << 0 << 0 << 4 << 0 << 7;
*set2 << 3 << 5 << 8 << 13 << 8 << 5;
*set3 << 5 << 6 << 7 << 3 << 4 << 5;
*set4 << 9 << 7 << 5 << 3 << 1 << 2;
//![1]
//![2]
QBarSeries *series = new QBarSeries();
series->append(set0);
series->append(set1);
series->append(set2);
series->append(set3);
series->append(set4);
//![2]
//![3]
QChart *chart = new QChart();
chart->addSeries(series);
chart->setTitle("Simple barchart example");
chart->setAnimationOptions(QChart::SeriesAnimations);
QGraphicsWidget *pLegend = new QGraphicsWidget(0);
QGraphicsGridLayout *pLegendLayout = new QGraphicsGridLayout(pLegend);
pLegend->setLayout(pLegendLayout);
pLegendLayout->setContentsMargins(1, 1, 1, 1);
QList<QColor> lstColor;
lstColor << QColor("#919b8e") << QColor("#9a7fd1") << QColor("#DC69AA") << QColor("#e01f54") << QColor("#339ca8") << QColor("2B821D");
//![3]
QList<QBarSet*> lstBar = series->barSets();
for (int i = 0; i < lstBar.size(); i++)
{
LegendItem *pItem = new LegendItem(chart, chart->layout());
pItem->setLegendItem(lstBar[i]->label(), lstColor[i], i, lstBar[i], series);
lstBar[i]->setColor(lstColor[i]);
pLegendLayout->addItem(pItem, i / 3, i % 3);
}
//![4]
QStringList categories;
categories << "Jan" << "Feb" << "Mar" << "Apr" << "May" << "Jun";
QBarCategoryAxis *axis = new QBarCategoryAxis();
axis->append(categories);
chart->createDefaultAxes();
chart->setAxisX(axis, series);
//![4]
//![5]
chart->legend()->setVisible(false);
chart->legend()->setAlignment(Qt::AlignBottom);
//![5]
//![6]
QChartView *chartView = new QChartView(chart);
chartView->setRenderHint(QPainter::Antialiasing);
chartView->chart()->scene()->addItem(pLegend);
chart->setMargins(QMargins(1, pLegend->minimumHeight(), 1,1));
pLegend->setMaximumWidth(chart->scene()->width());
pLegend->setPos(QPointF((chart->scene()->width()) / 2, 0));
pLegend->setAutoFillBackground(true);
//![6]
//![7]
QMainWindow window;
window.setCentralWidget(chartView);
window.resize(420, 300);
window.show();
//![7]
return a.exec();
}