60.QT-QabstractTableModel模型、重写sort方法排序
在之前25.QT-模型视图章节中,没有具体描述如何重写model模型,所以本章以QabstractTableModel为例,来谈谈model如何实现.
1.QabstractTableModel常用功能
QAbstractTableModel子类化时,必须覆写:
Int rowCount(); //返回显示的行数 int columnCount(); //返回显示的列数 Qvariant headerData(int section, Qt::Orientation orientation, int role); //返回标题role角色对应的值 // section:段号,从0开始,对于Qt::Horizontal水平标题,则是每列的标题名,对于Qt::Vertical垂直标题,则是每行的左侧标题名
//orientation:标题类型 //role:对应值是Qt:: ItemDataRole枚举, 对于role角色,常用的有: //Qt::DisplayRole :以文本方式显示数据(QString) //Qt::DecorationRole :将数据作为图标来装饰(QIcon,QPixmap) //Qt::EditRole :可编辑的数据信息显示(QString) //Qt::ToolTipRole :作为工具提示显示(QString) //Qt::StatusTipRole :作为状态栏中显示的数据(QString) //Qt::WhatsThisRole :作为帮助信息栏中显示的数据(QString) //Qt::FontRole :设置字体(QFont) //Qt::TextAlignmentRole :设置模型数据的文本对齐(Qt::AlignmentFlag) //Qt::BackgroundRole :设置模型数据的背景色(QBrush) //Qt::ForegroundRole : 设置模型数据的前景色,比如字体(QBrush) //Qt::SizeHintRole : 设置模型数据的大小
QVariant data(const QModelIndex &index, int role); //返回index单元格下的role角色数据。通过index可以获取行号和列号 bool setData(const QModelIndex &index, const QVariant &value, int role); //将index单元格下的role角色设置为value //对于可编辑模型,必须重写该函数,然后还需要重写flags() //返回值为true:表示设置成功,然后还需要显式发射dataChanged信号
2.QabstractTableModel可编辑功能
如果不想实现QabstractTableModel可编辑功能, 则调用QTableView ->setEditTriggers(QAbstractItemView::NoEditTriggers)即可.
如果要实现的话,则需要覆写下面函数:
Qt::ItemFlags flags(const QModelIndex &index); //设置每个单元格的flag,对于可编辑模型,必须重写它,添加Qt::ItemIsEditable(可编辑属性) //然后当我们双击时,会默认创建一个编辑组件(这是由 delegate 完成的)然后delegate会调用QAbstractTableModel ::data(index, Qt::EditRole)读取默认编辑值 //当我们编辑完成后, delegate会调用QAbstractTableModel :: setData (index, value, Qt::EditRole)告诉我们是否保存数据.
如果对于可调整行列的模型,可以重写insertRows()、removeRows()、insertColumns()、removeColumns().在实现这些函数时,还需要调用合适的父类函数,用来通知model调整了哪些内容:
insertRows(): //在向数据结构插入新行之前需要调用父类的beginInsertRows(),并且必须在之后立即调用endInsertRows()。 insertColumns(): //在向数据结构插入新列之前需要调用父类的beginInsertColumns(),并且必须在之后立即调用endInsertColumns()。 RemoveRows(): //在删除行之前需要调用父类的beginRemoveRows(),并且必须在之后立即调用endRemoveRows()。 RemoveColumns(): //在删除列之前需要调用父类的beginRemoveColumns(),并且必须在之后立即调用endRemoveColumns()。
注意:如果要重新刷新model数据,则必须在刷新model之前调用beginResetModel(),然后刷新之后调用endResetModel。
或者在刷新之后,emit dataChanged(index(0,0),index(rowCount,columnCount))来进行刷新视图
3.model排序之重写sort方法
首先需要调用QtableView->setSortingEnabled(true)使能排序,sort函数声明如下所示:
void sort(int column, Qt::SortOrder order = Qt::AscendingOrder); //当用户点击标题进行降序/升序排序时,会调用该方法 //或者调用QtableView->sortByColumn()时,也会调用该方法 // column:第几列进行排序 // order:升序(AscendingOrder)、降序(DescendingOrder)
排序方法则使用std::sort()来实现.然后写个sort类来配合column和order实现排序.
进行排序的时候,必须得调用beginResetModel(),endResetModel()进行界面刷新.
4.代码实现
界面如下所示,支持自定义排序:
下载链接:https://download.csdn.net/download/qq_37997682/13709956
custommodel.h如下所示:
#ifndef CUSTOMMODEL_H #define CUSTOMMODEL_H #include <QObject> #include <QAbstractTableModel> #include <QModelIndex> #include <QFont> #include <QPixmap> //排序类 class DataSort { public: int mColumn; Qt::SortOrder mSortOrder; DataSort(int column, Qt::SortOrder order) : mColumn(column) , mSortOrder(order) {} bool operator()(const QVector<QString>* v1, const QVector<QString>* v2) { int compare = 0; //>0:大于 <0:小于 bool ret=false; switch ( mColumn ) { case 0 : //序号,需要判断数字 case 3 : //信号ID,需要判断数字 compare = v1->at(mColumn).toInt() - v2->at(mColumn).toInt(); break; default : //其它,只判断字符串 compare = v1->at(mColumn).compare(v2->at(mColumn)); break; } if(compare==0) //相等必须返回flase,否则的话,对于一列相同的值进行降序,那么会一直返回true,从而死循环 { return false; } else ret = compare>0?false:true; if ( mSortOrder == Qt::DescendingOrder ) //降序 { ret = !ret; } return ret; } }; class CustomModel : public QAbstractTableModel { Q_OBJECT public: explicit CustomModel(QAbstractTableModel *parent = nullptr); 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 sort(int column, Qt::SortOrder order = Qt::AscendingOrder); public slots: void UpdateData(void); private: QList<QVector<QString> * > m_data; int m_columnCount; int m_rowCount; QFont m_Font; QPixmap m_icon; signals: }; #endif // CUSTOMMODEL_H
custommodel.cpp如下所示:
#include "custommodel.h" #include <QDateTime> #include <QDebug> CustomModel::CustomModel(QAbstractTableModel *parent) : QAbstractTableModel(parent) { m_columnCount = 5; //5行 m_rowCount = 60; m_Font.setFamily("Microsoft Yahei"); m_Font.setPixelSize(17); m_icon.load(":alarm"); m_icon = m_icon.scaled(20,22,Qt::KeepAspectRatio,Qt::SmoothTransformation); UpdateData(); } void CustomModel::UpdateData(void) { beginResetModel();
int count = m_data.size();
if(count > 0)
{
for(int i = 0; i < count; i++)
{
delete m_data.at(i);
}
m_data.clear();
}
for (int i = 0; i < m_rowCount; i++) { QVector<QString>* line = new QVector<QString>(m_columnCount); line->replace(0,QString("%1").arg(i+1)); line->replace(1,"显示器"); line->replace(2,"未显示"); line->replace(3,QString("%1").arg(qrand()%100)); line->replace(4,QDateTime::currentDateTime().addDays(-10).toString("hh:mm:ss")); m_data.append(line); } endResetModel(); //emit dataChanged(index(0,0),index(m_data.count()-1,columnCount()-1)); //和beginResetModel()、endResetModel() 本质一样 } int CustomModel::rowCount(const QModelIndex &parent) const { Q_UNUSED(parent) //由于parent未使用,所以通过Q_UNUSED去掉编译警告 return m_data.count(); } int CustomModel::columnCount(const QModelIndex &parent) const //列 { Q_UNUSED(parent) return m_columnCount; } QVariant CustomModel::headerData(int section, Qt::Orientation orientation, int role) const { if (role != Qt::DisplayRole) return QVariant(); if (orientation == Qt::Horizontal) { switch (section) { case 0 : return "序号"; case 1 : return "设备"; case 2 : return "状态"; case 3 : return "信号ID"; case 4 : return "上报时间"; default : return ""; } } else { return QString("%1").arg(section + 1); } } QVariant CustomModel::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::TextAlignmentRole) { //内容排版 return Qt::AlignCenter; } else if (role == Qt::FontRole) { //字体 return m_Font; } else if (role == Qt::DecorationRole) { //图标 if (index.column() == 2) return m_icon; } return QVariant(); } bool CustomModel::setData(const QModelIndex &index, const QVariant &value, int role) { if (index.isValid() && role == Qt::EditRole) { //编辑完成,保存数据到model,并返回true m_data[index.row()]->replace(index.column(), value.toString()); emit dataChanged(index, index); //重新实现setData()函数时,必须显式发出该信号。 return true; } return false; } Qt::ItemFlags CustomModel::flags(const QModelIndex &index) const { return QAbstractItemModel::flags(index) | Qt::ItemIsEditable; //设置item可编辑 } void CustomModel::sort(int column, Qt::SortOrder order) { beginResetModel(); DataSort comp(column,order); std::sort(m_data.begin(), m_data.end(),comp); endResetModel(); }
第二种排序方法则是通过使用QsortFilterProxyModel代理类实现排序,QsortFilterProxyModel类用来为model和view之间提供强大的排序和过滤支持,并且无需对模型中的数据进行任何转换,也无需对模型在中数据进行修改。
未完待续.下章学习:61.QT-QSortFilterProxyModel代理实现排序、过滤
人间有真情,人间有真爱。