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