参考qt自带的barmodelmapper例子
在原有的candlestickchart例子上修改代码,使其通过model来更新candlestickchart,其他图表也是通过这种方式来更新
代码:
MyTableWidget.h文件
#ifndef MYTABLEWIDGET_H
#define MYTABLEWIDGET_H
#include <QtWidgets/QWidget>
#include "customtablemodel.h"
class TableWidget : public QWidget
{
Q_OBJECT
public:
TableWidget(QWidget *parent = 0);
private:
CustomTableModel *m_model;
};
#endif // MYTABLEWIDGET_H
MyTableWidget.cpp
#include "MyTablewidget.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/QCategoryAxis>
#include <QtCharts/QDateTimeAxis>
#include <QtCharts/QValueAxis>
#include <QtCharts/QCandlestickSeries>
#include <QtCore/QDateTime>
#include <QtCharts/QHCandlestickModelMapper>
#include "candlestickdatareader.h"
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);
tableView->horizontalHeader()->setDefaultAlignment(Qt::AlignHCenter);
tableView->horizontalHeader()->setHighlightSections(false);
tableView->horizontalHeader()->setStretchLastSection(true);
tableView->verticalHeader()->setVisible(false);
m_model->setParent(tableView);
QCandlestickSeries *acmeSeries = new QCandlestickSeries();
//acmeSeries->setBodyOutlineVisible(false);
QPen p;
p.setColor(Qt::red);
acmeSeries->setPen(p);
// //acmeSeries->setCapsVisible(false);
acmeSeries->setBodyWidth(0.5);
// acmeSeries->setName("Acme Ltd");
acmeSeries->setIncreasingColor(QColor(Qt::red));
acmeSeries->setDecreasingColor(QColor(Qt::green));
QChart *chart = new QChart;
chart->setAnimationOptions(QChart::SeriesAnimations);
QHCandlestickModelMapper *mapper = new QHCandlestickModelMapper();
mapper->setOpenColumn(1); //设置open所在表格的哪一列
mapper->setCloseColumn(4);
mapper->setHighColumn(2);
mapper->setLowColumn(3);
mapper->setFirstSetRow(0);//设置第一条数据在表格的哪一行
mapper->setLastSetRow(21);
mapper->setTimestampColumn(0);
QPen p1;
mapper->setLastSetRow(22);
SharesKLineData* tmp = new SharesKLineData();
tmp->open = 120.0;
tmp->high = 123.0;
tmp->close = 119.0;
tmp->low = 118.80;
tmp->timestamp = 1438412932000;
m_model->addData(tmp);
mapper->setSeries(acmeSeries);
mapper->setModel(m_model);
chart->addSeries(acmeSeries);
// chart->setTitle("Acme Ltd Historical Data (July 2015)");
// chart->setAnimationOptions(QChart::SeriesAnimations);
QStringList categories;
QCategoryAxis *axisX1 = new QCategoryAxis();
QDateTimeAxis *axisX2 = new QDateTimeAxis();
QValueAxis *axisX3 = new QValueAxis();
axisX2->setFormat("yyyy-MM-dd");
axisX2->setTickCount(5);
//axisX2->
//axisX2
categories << "1" << "2" << "3" << "4" << "5"<<"6"<<"7"<<"8"<<"9"<<"10"<<"11"<<"12"<<"13"<<"14"<<"15"<<"16"<<"17"<<"18"<<"19"<<"20"<<"21"<<"22"<<"23";
QBarCategoryAxis *axisX = new QBarCategoryAxis();
axisX->append(categories);
axisX->setGridLineVisible(false);
axisX->setLineVisible(true);
axisX->setLabelsVisible(false);
chart->addAxis(axisX, Qt::AlignBottom);
acmeSeries->attachAxis(axisX);
// chart->addAxis(axisX3,Qt::AlignBottom);
// acmeSeries->attachAxis(axisX3);
QValueAxis *axisY = new QValueAxis();
chart->addAxis(axisY, Qt::AlignRight);
acmeSeries->attachAxis(axisY);
chart->legend()->setVisible(false);
// //! [3]
// //! [4]
// chart->createDefaultAxes();
// QBarCategoryAxis *axisX = qobject_cast<QBarCategoryAxis *>(chart->axes(Qt::Horizontal).at(0));
// axisX->setCategories(categories);
// QValueAxis *axisY = qobject_cast<QValueAxis *>(chart->axes(Qt::Vertical).at(0));
// axisY->setMax(axisY->max() * 1.01);
// axisY->setMin(axisY->min() * 0.99);
// //! [4]
// //! [5]
// chart->legend()->setVisible(true);
// chart->legend()->setAlignment(Qt::AlignBottom);
// //! [5]
// //! [6]
QChartView *chartView = new QChartView(chart);
chartView->setRenderHint(QPainter::Antialiasing);
// //! [6]
QGridLayout *mainLayout = new QGridLayout;
mainLayout->addWidget(tableView, 1, 0);
mainLayout->addWidget(chartView, 1, 1);
mainLayout->setColumnStretch(1, 1);
mainLayout->setColumnStretch(0, 0);
setLayout(mainLayout);
resize(1100, 600);
for(int i = 0;i<acmeSeries->sets().size();i++)
{
if(acmeSeries->sets().at(i)->open() < acmeSeries->sets().at(i)->close())
p1.setColor(Qt::red);
else if(acmeSeries->sets().at(i)->open() > acmeSeries->sets().at(i)->close())
p1.setColor(Qt::green);
else
p1.setColor(Qt::black);
acmeSeries->sets().at(i)->setPen(p1);
}
}
candlestickdatareader.h文件
#ifndef CANDLESTICKDATAREADER_H
#define CANDLESTICKDATAREADER_H
#include <QtCharts/QCandlestickSet>
#include <QtCore/QTextStream>
#include "Types.h"
QT_CHARTS_USE_NAMESPACE
class CandlestickDataReader : public QTextStream
{
public:
explicit CandlestickDataReader(QIODevice *device);
~CandlestickDataReader();
void readFile(QIODevice *device);
QCandlestickSet *readCandlestickSet();
SharesKLineData* readShareKlineData();
};
#endif // CANDLESTICKDATAREADER_H
candlestickdatareader.cpp文件
#include "candlestickdatareader.h"
CandlestickDataReader::CandlestickDataReader(QIODevice *device)
: QTextStream(device)
{
}
CandlestickDataReader::~CandlestickDataReader()
{
}
void CandlestickDataReader::readFile(QIODevice *device)
{
QTextStream::setDevice(device);
}
QCandlestickSet *CandlestickDataReader::readCandlestickSet()
{
//! [1]
QString line = readLine();
if (line.startsWith("#") || line.isEmpty())
return 0;
//! [1]
//! [2]
QStringList strList = line.split(" ", QString::SkipEmptyParts);
if (strList.count() != 5)
return 0;
//! [2]
//! [3]
const qreal timestamp = strList.at(0).toDouble();
const qreal open = strList.at(1).toDouble();
const qreal high = strList.at(2).toDouble();
const qreal low = strList.at(3).toDouble();
const qreal close = strList.at(4).toDouble();
//! [3]
//! [4]
QCandlestickSet *candlestickSet = new QCandlestickSet(timestamp);
candlestickSet->setOpen(open);
candlestickSet->setHigh(high);
candlestickSet->setLow(low);
candlestickSet->setClose(close);
//! [4]
return candlestickSet;
}
SharesKLineData* CandlestickDataReader::readShareKlineData()
{
//! [1]
QString line = readLine();
if (line.startsWith("#") || line.isEmpty())
return 0;
//! [1]
//! [2]
QStringList strList = line.split(" ", QString::SkipEmptyParts);
if (strList.count() != 5)
return 0;
//! [2]
//! [3]
const qreal timestamp = strList.at(0).toDouble();
const qreal open = strList.at(1).toDouble();
const qreal high = strList.at(2).toDouble();
const qreal low = strList.at(3).toDouble();
const qreal close = strList.at(4).toDouble();
//! [3]
SharesKLineData* datas = new SharesKLineData();
datas->timestamp = timestamp;
datas->open = open;
datas->high = high;
datas->low = low;
datas->close = close;
return datas;
}
customtablemodel.h
#ifndef CUSTOMTABLEMODEL_H
#define CUSTOMTABLEMODEL_H
#include <QtCore/QAbstractTableModel>
#include <QtCore/QHash>
#include <QtCore/QRect>
#include "Types.h"
class CustomTableModel : public QAbstractTableModel
{
Q_OBJECT
public:
explicit CustomTableModel(QObject *parent = 0);
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(); }
void addData(SharesKLineData*dataObj);
private:
QList<QVector<qreal> * > m_data;
QHash<QString, QRect> m_mapping;
QList<SharesKLineData> m_klineList;
QStringList table_header;
int m_columnCount;
int m_rowCount;
};
#endif // CUSTOMTABLEMODEL_H
customtablemodel.cpp
#include "customtablemodel.h"
#include <QtCore/QVector>
#include <QtCore/QTime>
#include <QtCore/QRect>
#include <QtCore/QRandomGenerator>
#include <QtGui/QColor>
#include "candlestickdatareader.h"
CustomTableModel::CustomTableModel(QObject *parent) :
QAbstractTableModel(parent)
{
m_columnCount = 5;
m_rowCount = 12;
// m_data
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);
}
QFile acmeData(":acme");
if (!acmeData.open(QIODevice::ReadOnly | QIODevice::Text))
{
}
CandlestickDataReader dataReader(&acmeData);
while (!dataReader.atEnd()) {
SharesKLineData* tmpData = dataReader.readShareKlineData();
if(tmpData)
{
m_klineList.append(*tmpData);
}
}
m_rowCount = m_klineList.size();
table_header<< "timestamp"<<"open"<< "high"<<"low"<< "close";
}
CustomTableModel::~CustomTableModel()
{
qDeleteAll(m_data);
//qDeleteAll(m_klineList);
}
int CustomTableModel::rowCount(const QModelIndex &parent) const
{
Q_UNUSED(parent)
//return m_data.count();
return m_klineList.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)
{
if(orientation == Qt::Horizontal)
{
if(table_header.size() > section)
return table_header[section];
else
return QVariant();
}
}
}
QVariant CustomTableModel::data(const QModelIndex &index, int role) const
{
if (!index.isValid() || index.row() > m_klineList.count())
{
return QVariant();
}
// FIXME: Implement me!
int nColumn = index.column();
int row = index.row(); //行号
if (role == Qt::DisplayRole) {
//return m_data[index.row()]->at(index.column());
switch(nColumn)
{
case 0:
return m_klineList[index.row()].timestamp;
break;
case 1:
{
return m_klineList[index.row()].open;
}
break;
case 2:
return m_klineList[index.row()].high;
break;
case 3:
return m_klineList[index.row()].low;
break;
case 4:
return m_klineList[index.row()].close;
break;
}
} else if (role == Qt::EditRole) {
switch(nColumn)
{
case 0:
return m_klineList[index.row()].timestamp;
break;
case 1:
{
return m_klineList[index.row()].open;
}
break;
case 2:
return m_klineList[index.row()].high;
break;
case 3:
return m_klineList[index.row()].low;
break;
case 4:
return m_klineList[index.row()].close;
break;
}
} else if (role == Qt::BackgroundRole) {
for (const QRect &rect : m_mapping) {
if (rect.contains(index.column(), index.row()))
return QColor(m_mapping.key(rect));
}
// cell not mapped return white color
return QColor(Qt::white);
}
return QVariant();
}
bool CustomTableModel::setData(const QModelIndex &index, const QVariant &value, int role)
{
int nColumn = index.column();
if (index.isValid() && role == Qt::EditRole) {
switch(nColumn)
{
case 0:
m_klineList[index.row()].timestamp = value.toDouble();
break;
case 1:
{
m_klineList[index.row()].open = value.toDouble();
}
break;
case 2:
m_klineList[index.row()].high = value.toDouble();
break;
case 3:
m_klineList[index.row()].low = value.toDouble();
break;
case 4:
m_klineList[index.row()].close = value.toDouble();
break;
}
//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);
}
void CustomTableModel::addData(SharesKLineData *dataObj)
{
beginResetModel();
m_klineList.push_back(*dataObj);
endResetModel();
}
Types.h
#ifndef TYPES_H
#define TYPES_H
#include <QtCore>
typedef struct SharesKLineData
{
QString day;
qreal timestamp;
double open;
double high;
double low;
double close;
qlonglong volume;
double ma_price5;
quint32 ma_volume5;
double ma_price10;
quint32 ma_volume10;
double ma_price20;
quint32 ma_volume20;
double ma_price30;
quint32 ma_volume30;
}SharesKLineData;
#endif // TYPES_H
main.cpp
#include <QtCharts/QBarCategoryAxis>
#include <QtCharts/QCandlestickSeries>
#include <QtCharts/QChartView>
#include <QtCharts/QValueAxis>
#include <QtCore/QDateTime>
#include <QtWidgets/QApplication>
#include <QtWidgets/QMainWindow>
#include <QtCharts/QVCandlestickModelMapper>
#include <QtCharts/QHCandlestickModelMapper>
#include "candlestickdatareader.h"
#include "MyTablewidget.h"
QT_CHARTS_USE_NAMESPACE
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
TableWidget w;
w.show();
return a.exec();
}
数据文件就是candlestickchart例子中的acme文件
# Acme Ltd Historical Data (July 2015)
# timestamp, open, high, low, close
1435708800000 126.90 126.94 125.99 126.60
1435795200000 126.69 126.69 126.69 126.69
1436140800000 124.85 126.23 124.85 126.00
1436227200000 125.89 126.15 123.77 125.69
1436313600000 124.64 124.64 122.54 122.54
1436400000000 123.85 124.06 119.22 120.07
1436486400000 121.94 123.85 121.21 123.28
1436745600000 125.03 125.76 124.32 125.66
1436832000000 126.04 126.37 125.04 125.61
1436918400000 125.72 127.15 125.58 126.82
1437004800000 127.74 128.57 127.35 128.51
1437091200000 129.08 129.62 128.31 129.62
1437350400000 130.97 132.97 130.70 132.07
1437436800000 132.85 132.92 130.32 130.75
1437523200000 121.99 125.50 121.99 125.22
1437609600000 126.20 127.09 125.06 125.16
1437696000000 125.32 125.74 123.90 124.50
1437955200000 123.09 123.61 122.12 122.77
1438041600000 123.38 123.91 122.55 123.38
1438128000000 123.15 123.50 122.27 122.99
1438214400000 122.32 122.57 121.71 122.37
1438300800000 122.60 122.64 120.91 121.30