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();
}
实际运行效果图:
总结
在实际项目中会经常用到类似的数据模型,非常方便使用的。