QTChart实现柱状图的mvc模型

简介: QTChart实现柱状图的mvc模型

QT MVC模型

QT MVC(Model-View-Controller)模型是QT框架的一种设计模式,用于实现应用程序的分层结构和分离关注点。MVC模型将应用程序分为三个部分:模型(Model)、视图(View)和控制器(Controller)。


模型(Model):模型是应用程序的数据和业务逻辑部分。它负责存储应用程序的数据和定义操作数据的方法。模型是不依赖于视图的的部分,它应该是一个独立的的数据结构和算法集合。

视图(View):视图是应用程序的UI部分,它负责展示模型中的数据和呈现用户界面。视图可以直接访问模型,但是它应该只读取模型中的数据而不应该修改模型。视图应该能够动态地反映出模型的变化。

控制器(Controller):控制器是应用程序的事件处理部分,它负责处理用户输入并更新模型。控制器监听用户输入设备(如鼠标、键盘等)的事件,并根据事件类型更新模型。控制器应该是一个被动部分,它不应该直接修改模型或视图,而是通过信号和槽机制来实现。

在MVC模型中,模型、视图和控制器之间通过信号和槽机制进行通信。模型发出数据变化信号,视图通过槽函数监听该信号并更新视图。同样地,控制器也通过信号和槽机制监听用户输入事件并更新模型。通过MVC模型,应用程序实现了数据、业务逻辑和UI的分离,提高了代码的可维护性和可扩展性。

举例代码

CustomTableModel.hpp

#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 = 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(); }
private:
    QList<QVector<qreal> * > m_data;
    QHash<QString, QRect> m_mapping;
    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>
/**
 * @brief CustomTableModel::CustomTableModel  抽象的数据模型
 * @param parent
 */
CustomTableModel::CustomTableModel(QObject *parent) :
    QAbstractTableModel(parent)
{
    m_columnCount = 6;
    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);
    }
}
CustomTableModel::~CustomTableModel()
{
    qDeleteAll(m_data);
}
/**
 * @brief CustomTableModel::rowCount 获取数据行数
 * @param parent
 * @return
 */
int CustomTableModel::rowCount(const QModelIndex &parent) const
{
    Q_UNUSED(parent)
    return m_data.count();
}
/**
 * @brief CustomTableModel::columnCount  数据列数
 * @param parent
 * @return
 */
int CustomTableModel::columnCount(const QModelIndex &parent) const
{
    Q_UNUSED(parent)
    return m_columnCount;
}
/**
 * @brief CustomTableModel::headerData 数据的表头信息
 * @param section
 * @param orientation
 * @param role
 * @return
 */
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);
}
/**
 * @brief CustomTableModel::data  数据信息
 * @param index
 * @param role
 * @return
 */
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));
        }
        // cell not mapped return white color
        return QColor(Qt::white);
    }
    return QVariant();
}
/**
 * @brief CustomTableModel::setData 数据可以修改的
 * @param index
 * @param value
 * @param role
 * @return
 */
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;
}
/**
 * @brief CustomTableModel::flags 设置状态标识
 * @param index
 * @return
 */
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);
}

tablewiget代码如下:

#include "tablewidget.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>
QT_CHARTS_USE_NAMESPACE
TableWidget::TableWidget(QWidget *parent)
    : QWidget(parent)
{
    // create simple model for storing data
    // user's table data model
    //! [1]
    m_model = new CustomTableModel;
    //! [1]
    //! [2]
    // create table view and add model to it
    QTableView *tableView = new QTableView;
    tableView->setModel(m_model);
    tableView->setMinimumWidth(300);
    tableView->horizontalHeader()->setSectionResizeMode(QHeaderView::Stretch);
    tableView->verticalHeader()->setSectionResizeMode(QHeaderView::Stretch);
    m_model->setParent(tableView);
    //! [2]
    //! [3]
    QChart *chart = new QChart;
    chart->setAnimationOptions(QChart::AllAnimations);
    //! [3]
    // series 1
    //! [4]
    QBarSeries *series = new QBarSeries;
    int first = 1;
    int count = 6;
    QVBarModelMapper *mapper = new QVBarModelMapper(this);
    mapper->setFirstBarSetColumn(0);
    mapper->setLastBarSetColumn(5);
    mapper->setFirstRow(first);
    mapper->setRowCount(count);
    mapper->setSeries(series);
    mapper->setModel(m_model);
    chart->addSeries(series);
    //! [4]
    //! [5]
    // for storing color hex from the series
    QString seriesColorHex = "#000000";
    // get the color of the series and use it for showing the mapped area
    QList<QBarSet *> barsets = series->barSets();
    for (int i = 0; i < barsets.count(); i++) {
        seriesColorHex = "#" + QString::number(barsets.at(i)->brush().color().rgb(), 16).right(6).toUpper();
        m_model->addMapping(seriesColorHex, QRect( i, first, 1, barsets.at(i)->count()));
    }
    //! [5]
    //! [6]
    QStringList categories;
    categories << "April" << "May" << "June" << "July" << "August" <<"surptember";
    QBarCategoryAxis *axisX = new QBarCategoryAxis();
    axisX->append(categories);
    chart->addAxis(axisX, Qt::AlignBottom);
    series->attachAxis(axisX);
    QValueAxis *axisY = new QValueAxis();
    chart->addAxis(axisY, Qt::AlignLeft);
    series->attachAxis(axisY);
    //! [6]
    //! [7]
    QChartView *chartView = new QChartView(chart);
    chartView->setRenderHint(QPainter::Antialiasing);
    chartView->setMinimumSize(640, 480);
    //! [7]
    //! [8]
    // create main layout
    QGridLayout *mainLayout = new QGridLayout;
    mainLayout->addWidget(tableView, 1, 0);
    mainLayout->addWidget(chartView, 1, 1);
    mainLayout->setColumnStretch(1, 1);
    mainLayout->setColumnStretch(0, 0);
    setLayout(mainLayout);
    //! [8]
}

main.cpp如下:

#include <QtWidgets/QApplication>
#include "tablewidget.h"
int main(int argc, char *argv[])
{
    QApplication a(argc, argv);
    TableWidget w;
    w.show();
    return a.exec();
}

实际运行效果图:

总结

在实际项目中会经常用到类似的数据模型,非常方便使用的。

相关实践学习
基于Hologres轻松玩转一站式实时仓库
本场景介绍如何利用阿里云MaxCompute、实时计算Flink和交互式分析服务Hologres开发离线、实时数据融合分析的数据大屏应用。
阿里云实时数仓实战 - 项目介绍及架构设计
课程简介 1)学习搭建一个数据仓库的过程,理解数据在整个数仓架构的从采集、存储、计算、输出、展示的整个业务流程。 2)整个数仓体系完全搭建在阿里云架构上,理解并学会运用各个服务组件,了解各个组件之间如何配合联动。 3&nbsp;)前置知识要求 &nbsp; 课程大纲 第一章&nbsp;了解数据仓库概念 初步了解数据仓库是干什么的 第二章&nbsp;按照企业开发的标准去搭建一个数据仓库 数据仓库的需求是什么 架构 怎么选型怎么购买服务器 第三章&nbsp;数据生成模块 用户形成数据的一个准备 按照企业的标准,准备了十一张用户行为表 方便使用 第四章&nbsp;采集模块的搭建 购买阿里云服务器 安装 JDK 安装 Flume 第五章&nbsp;用户行为数据仓库 严格按照企业的标准开发 第六章&nbsp;搭建业务数仓理论基础和对表的分类同步 第七章&nbsp;业务数仓的搭建&nbsp; 业务行为数仓效果图&nbsp;&nbsp;
相关文章
|
5天前
|
前端开发 Java PHP
信息系统架构模型(1) MVC
信息系统架构模型(1) MVC
13 0
|
1月前
|
设计模式 前端开发 数据处理
MVC架构中,控制器和模型之间是如何交互的
MVC架构中,控制器和模型之间是如何交互的
12 0
|
1月前
|
存储 设计模式 前端开发
请解释 Web 应用程序的 MVC(模型-视图-控制器)架构。
【2月更文挑战第26天】【2月更文挑战第89篇】请解释 Web 应用程序的 MVC(模型-视图-控制器)架构。
|
4月前
|
前端开发 JavaScript Java
让你了解什么是spring MVC模型数据(附大量代码)
让你了解什么是spring MVC模型数据(附大量代码)
45 0
|
7月前
|
前端开发
MVC模型
MVC模型
34 0
|
9月前
|
开发框架 前端开发 安全
ASP.NET Core MVC 从入门到精通之Html辅助标签补充及模型校验基础
ASP.NET Core MVC 从入门到精通之Html辅助标签补充及模型校验基础
93 0
|
11月前
|
前端开发 网络协议 Java
02.【基础】sdk和runtime区别及让你一睹为快使用CLI在CentOS上快速搭建Console,WebApi,MVC三大应用模型
02.【基础】sdk和runtime区别及让你一睹为快使用CLI在CentOS上快速搭建Console,WebApi,MVC三大应用模型
180 0
|
设计模式 存储 前端开发
Python:设计模式之模型-视图-控制器-MVC复合模式
Python:设计模式之模型-视图-控制器-MVC复合模式
75 0
|
前端开发
.NET MVC第五章、模型绑定获取表单数据
.NET MVC第五章、模型绑定获取表单数据
58 0
.NET MVC第五章、模型绑定获取表单数据