这个示例的内容主要有两个知识点:
- 自定义数据模型的方法。
- 条形图的数据模型映射器 QVBarModelMapper 类的用法。
自定义数据模型:使用随机数据作为模型的数据:
#ifndef CUSTOMTABLEMODEL_H
#define CUSTOMTABLEMODEL_H
#include <QtCore/QAbstractTableModel>
#include <QtCore/QHash>
#include <QtCore/QRect>
class CustomTableModel : public QAbstractTableModel
{
Q_OBJECT
public:
explicit CustomTableModel(QObject *parent = nullptr);
virtual ~CustomTableModel();
int rowCount(const QModelIndex &parent = QModelIndex()) const;
int columnCount(const QModelIndex &parent = QModelIndex()) const;
QVariant headerData(int section, Qt::Orientation orientation, int role = Qt::DisplayRole) const;
QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const;
bool setData(const QModelIndex &index, const QVariant &value, int role = Qt::EditRole);
Qt::ItemFlags flags(const QModelIndex &index) const;
void addMapping(QString color, QRect area);
void clearMapping() { m_mapping.clear(); }
private:
QList<QVector<qreal> * > m_data;
QHash<QString, QRect> m_mapping;
int m_columnCount;
int m_rowCount;
};
#endif // CUSTOMTABLEMODEL_H
#include "customtablemodel.h"
#include <QtCore/QVector>
#include <QtCore/QTime>
#include <QtCore/QRect>
#include <QtCore/QRandomGenerator>
#include <QtGui/QColor>
CustomTableModel::CustomTableModel(QObject *parent) :
QAbstractTableModel(parent)
{
m_columnCount = 6;
m_rowCount = 12;
for (int i = 0; i < m_rowCount; i++)
{
QVector<qreal>* dataVec = new QVector<qreal>(m_columnCount);
for (int k = 0; k < dataVec->size(); k++)
{
if (k % 2 == 0)
dataVec->replace(k, i * 50 + QRandomGenerator::global()->bounded(20));
else
dataVec->replace(k, QRandomGenerator::global()->bounded(100));
}
m_data.append(dataVec);
}
}
CustomTableModel::~CustomTableModel()
{
qDeleteAll(m_data);
}
int CustomTableModel::rowCount(const QModelIndex &parent) const
{
Q_UNUSED(parent)
return m_data.count();
}
int CustomTableModel::columnCount(const QModelIndex &parent) const
{
Q_UNUSED(parent)
return m_columnCount;
}
QVariant CustomTableModel::headerData(int section, Qt::Orientation orientation, int role) const
{
if (role != Qt::DisplayRole)
return QVariant();
if (orientation == Qt::Horizontal)
return QString("201%1年").arg(section);
else
return QString("%1月").arg(section + 1);
}
QVariant CustomTableModel::data(const QModelIndex &index, int role) const
{
if (role == Qt::DisplayRole)
{
return m_data[index.row()]->at(index.column());
}
else if (role == Qt::EditRole)
{
return m_data[index.row()]->at(index.column());
}
else if (role == Qt::BackgroundRole)
{
for (const QRect &rect : m_mapping)
{
if (rect.contains(index.column(), index.row()))
return QColor(m_mapping.key(rect));
}
return QColor(Qt::white);// 未映射的单元格返回白色
}
return QVariant();
}
bool CustomTableModel::setData(const QModelIndex &index, const QVariant &value, int role)
{
if (index.isValid() && role == Qt::EditRole)
{
m_data[index.row()]->replace(index.column(), value.toDouble());//编辑数据后容器里的数据也跟着变化
emit dataChanged(index, index);
return true;
}
return false;
}
Qt::ItemFlags CustomTableModel::flags(const QModelIndex &index) const
{
return QAbstractItemModel::flags(index) | Qt::ItemIsEditable;//可编辑
}
void CustomTableModel::addMapping(QString color, QRect area)
{
m_mapping.insertMulti(color, area);
}
关于自定义模型,还可以参考:自定义模型。
上面这个模型唯一的特别之处在于:默认是白色背景,在一些特别位置数据的背景色是设置的其他颜色。
主界面:
#include "tablewidget.h"
#include "customtablemodel.h"
#include <QtWidgets/QGridLayout>
#include <QtWidgets/QTableView>
#include <QtCharts/QChart>
#include <QtCharts/QChartView>
#include <QtCharts/QLineSeries>
#include <QtCharts/QVXYModelMapper>
#include <QtCharts/QBarSeries>
#include <QtCharts/QBarSet>
#include <QtCharts/QVBarModelMapper>
#include <QtWidgets/QHeaderView>
#include <QtCharts/QBarCategoryAxis>
#include <QtCharts/QValueAxis>
#include <QDebug>
QT_CHARTS_USE_NAMESPACE
TableWidget::TableWidget(QWidget *parent)
: QWidget(parent)
{
m_model = new CustomTableModel;
QTableView *tableView = new QTableView;
tableView->setModel(m_model);
tableView->setMinimumWidth(400);
tableView->horizontalHeader()->setSectionResizeMode(QHeaderView::Stretch);
tableView->verticalHeader()->setSectionResizeMode(QHeaderView::Stretch);
m_model->setParent(tableView);
QBarSeries *series = new QBarSeries;//条形图
int first = 3;
QVBarModelMapper *mapper = new QVBarModelMapper(this);
mapper->setFirstBarSetColumn(1);//条形集的数据源的模型列,第一列开始,共4列
mapper->setLastBarSetColumn(4);
mapper->setFirstRow(first);//第3行开始,共5行
mapper->setRowCount(5);
mapper->setSeries(series);
mapper->setModel(m_model);
QChart *chart = new QChart;
chart->setAnimationOptions(QChart::AllAnimations);
chart->addSeries(series);
//获取条形图的颜色并将其用于显示映射区域
QList<QBarSet *> barsets = series->barSets();//4
for (int i = 0; i < barsets.count(); ++i)
{
QBarSet * bar = barsets.at(i);
QString seriesColorHex = "#" + QString::number(bar->brush().color().rgb(),16).right(6).toUpper();
QRect rect = QRect(1 + i, first, 1, bar->count());//bar->count() = 5
m_model->addMapping(seriesColorHex, rect);
qDebug()<<seriesColorHex<<" "<<rect;
}
QBarCategoryAxis *axisX = new QBarCategoryAxis();//条形图坐标轴
axisX->append(QStringList() << "四月" << "五月" << "六月" << "七月" << "八月");
chart->addAxis(axisX, Qt::AlignBottom);
series->attachAxis(axisX);
QValueAxis *axisY = new QValueAxis();
chart->addAxis(axisY, Qt::AlignLeft);
series->attachAxis(axisY);
QChartView *chartView = new QChartView(chart);
chartView->setRenderHint(QPainter::Antialiasing);
chartView->setMinimumSize(640, 480);
QGridLayout *mainLayout = new QGridLayout;
mainLayout->addWidget(tableView, 1, 0);
mainLayout->addWidget(chartView, 1, 1);
mainLayout->setColumnStretch(1, 1);
mainLayout->setColumnStretch(0, 0);
setLayout(mainLayout);
}
可见模型的列名称被用作图表的图例。
改变模型中的数据图表跟着变化。
反过来,用一个定时器定时改变图表中的数据:
QTimer * timer = new QTimer(this);
connect(timer,&QTimer::timeout,this,[series]()mutable
{
QBarSet * bar = series->barSets()[0];
bar->replace(2,QRandomGenerator::global()->bounded(300));
});
timer->start(1000);
模型中的数据也会同步变化。
示例中的一个小技巧,颜色转16进制字符串:
QColor color;
QString seriesColorHex = "#" + QString::number(color.rgb(),16).right(6).toUpper();