继承QAbstractTableModel QStyledItemDelegate实现自定义表格,添加进度条和选中框。
由于项目要求,需要实现一个列表目录显示信息,并且需要实现每一项提供进度条和选项框功能,所以需要继承QAbstractTableModel和QStyledItemDelegate进行自定义。
-自定义数据
itemdata.h
#ifndef ITEMDATA_H #define ITEMDATA_H #include <QMetaType> #include <QString> #include <QDebug> typedef enum{ level_0 = 0, level_1, level_2, level_3, level_4, level_5, level_6, level_7, level_8, level_9, level_none, } Priority; typedef enum{ state_0 = 0, state_1, state_2, state_3, state_4, state_5, state_6, state_7, state_8, state_9, }State; struct Data{ Priority priority; State taskState; QString taskCode; QString taskName; QString taskType; QString tubeType; int tubeNumber; int rackNumber; int beginTime; int processed; //[0-100] QString taskOwner; bool select = false; }; Q_DECLARE_METATYPE(Data) #endif // ITEMDATA_H
-继承QAbstractTableModel自定义数据
mytablemodel.h
#ifndef MYTABLEMODEL_H
#define MYTABLEMODEL_H #include<QAbstractTableModel> #include <QList> #include "itemdata.h" class myTableModel:public QAbstractTableModel { Q_OBJECT public: myTableModel(QAbstractTableModel *parent = 0); ~myTableModel(); QVariant data(const QModelIndex &index, int role) const;// 重写,用于返回数据 int rowCount(const QModelIndex &parent = QModelIndex()) const; // 重写, 反回行数 int columnCount(const QModelIndex &parent = QModelIndex()) const;// 重写,返回列数 QVariant headerData(int section, Qt::Orientation, int role)const;// 重写, 返回列标题 Qt::ItemFlags flags(const QModelIndex &index) const; // 重写, 每一项的操作标识 bool setData(const QModelIndex &index, const QVariant &value, int role = Qt::EditRole);// 重写, 设置数据 void addData(Data data);// 添加模型数据 private: QStringList _roleNames; QList<Data> _dataList; }; #endif // MYTABLEMODEL_H
#include "mytablemodel.h" myTableModel::myTableModel(QAbstractTableModel *parent):QAbstractTableModel(parent), _roleNames({"priority","taskState","taskCode","taskName","taskType","tubeType","tubeNumber","rackNumber","beginTime","processed","taskOwner","select"}){ } myTableModel::~myTableModel(){ } QVariant myTableModel::data(const QModelIndex &index, int role) const{ QVariant v; switch (role - (Qt::UserRole+1)) {// 自定义角色从Qt::UserRole + 1开始 case 0: v = QVariant(_dataList[index.row()].priority); break; case 1: v = QVariant(_dataList[index.row()].taskState); break; case 2: v = QVariant(_dataList[index.row()].taskCode); break; case 3: v = QVariant(_dataList[index.row()].taskName); break; case 4: v = QVariant(_dataList[index.row()].taskType); break; case 5: v = QVariant(_dataList[index.row()].tubeType); break; case 6: v = QVariant(_dataList[index.row()].tubeNumber); break; case 7: v = QVariant(_dataList[index.row()].rackNumber); break; case 8: v = QVariant(_dataList[index.row()].beginTime); break; case 9: v = QVariant(_dataList[index.row()].processed); break; case 10: v = QVariant(_dataList[index.row()].taskOwner); break; case 11: v= QVariant(_dataList[index.row()].select); break; } return v; } int myTableModel::rowCount(const QModelIndex &parent) const { Q_UNUSED(parent) return _dataList.size();// 行数 } int myTableModel::columnCount(const QModelIndex &parent) const { Q_UNUSED(parent) return _roleNames.size();//列数 } //QHash<int, QByteArray> myTableModel::roleNames() const //{ // QHash<int,QByteArray> roleName; // for(int i = 0; i < _roleNames.size(); ++i){ // roleName.insert(Qt::UserRole+1+i,_roleNames[i].toLocal8Bit()); // } // return roleName; //} QVariant myTableModel::headerData(int section, Qt::Orientation orientation, int role)const{ if(role == Qt::DisplayRole && orientation == Qt::Orientation::Horizontal){ //返回列标题 QString sectionName; switch (section) { case 0: sectionName = tr("优先级"); break; case 1: sectionName = tr("状态"); break; case 2: sectionName = tr("编码"); break; case 3: sectionName = tr("名称"); break; case 4: sectionName = tr("类型"); break; case 5: sectionName = tr("冻存管型号"); break; case 6: sectionName = tr("管数量"); break; case 7: sectionName = tr("盒数量"); break; case 8: sectionName = tr("开始时间"); break; case 9: sectionName = tr("进度"); break; case 10: sectionName = tr("发起人"); break; case 11: sectionName = tr("选中"); break; } return sectionName; } return QVariant(); } void myTableModel::addData(Data data){ beginInsertRows(QModelIndex(),_dataList.count(),_dataList.count()); //添加数据之前进行通知并告知添加到什么位置 _dataList.push_back(data); endInsertRows(); } Qt::ItemFlags myTableModel::flags(const QModelIndex &index) const { if(!index.isValid()){ return Qt::NoItemFlags; } Qt::ItemFlags flags; flags = QAbstractItemModel::flags(index); if(index.column() == 11){ flags |= Qt::ItemIsEnabled | Qt::ItemIsSelectable | Qt::ItemIsUserCheckable|Qt::ItemIsUserCheckable;// 选项框设置为可选中 } else { flags |= Qt::ItemIsEnabled | Qt::ItemIsSelectable | Qt::ItemIsUserCheckable; } return flags; } bool myTableModel::setData(const QModelIndex &index, const QVariant &value, int role) { if(role == Qt::UserRole + 1 + 11){// 设置选项框数据true or false QVector<int> changeRoles; changeRoles.push_back(Qt::UserRole + 1 + 11); for(QList<Data>::iterator it = _dataList.begin(); it != _dataList.end(); ++it){ if((*it).taskCode == index.data(Qt::UserRole +1 + 2).toString()){ // 根据taskCode定位选中的数据行 (*it).select = value.toBool(); } } emit dataChanged(index,index,changeRoles); return true; } else{ return QAbstractTableModel::setData(index, index,role); // 调用默认父类默认实现 } }
-继承QStyledItemDelegate重写数据项代理,显示各个项,并接收接收处理用户事件
myitemdelegate.h
#ifndef MYITEMDELEGATE_H #define MYITEMDELEGATE_H #include <QStyledItemDelegate> #include <QPainter> #include <QStyleOptionViewItem> #include <QRect> #include <QPainterPath> #include <QDate> #include <QTime> #include <QApplication> #include "itemdata.h" class myItemDelegate:public QStyledItemDelegate { Q_OBJECT public: myItemDelegate(QStyledItemDelegate * parent = 0); ~myItemDelegate(); void paint(QPainter * painter,const QStyleOptionViewItem & option,const QModelIndex & index) const; // 重写,绘制每一项 QSize sizeHint(const QStyleOptionViewItem &option, const QModelIndex &index) const;//重写, 返回项尺寸 bool editorEvent(QEvent *event, QAbstractItemModel *model, const QStyleOptionViewItem &option, const QModelIndex &index);// 重写,处理项事件 QRect checkBoxRect(const QStyleOptionViewItem &viewItemStyleOptions) const;//返回选中框尺寸 }; #endif // MYITEMDELEGATE_H
#include "myitemdelegate.h" #include <QMouseEvent> myItemDelegate::myItemDelegate(QStyledItemDelegate *parent):QStyledItemDelegate(parent) { } myItemDelegate::~myItemDelegate(){ } void myItemDelegate::paint(QPainter *painter, const QStyleOptionViewItem &option, const QModelIndex &index) const{ if(index.isValid()){ painter->save(); int column = index.column(); QVariant v = index.data(column + (Qt::UserRole+1)); //获取数据 // painter->drawRect(option.rect); QStyleOptionViewItem viewOption(option); if(0 == column){ Priority priority = (Priority)v.toInt(); painter->drawText(option.rect, Qt::AlignCenter, QString::number(priority)); }else if(1 == column){ State state = (State)v.toInt(); painter->drawText(option.rect, Qt::AlignCenter, QString::number(state)); } else if(2 == column){ QString taskCode = v.toString(); painter->drawText(option.rect, Qt::AlignCenter,taskCode); } else if(3 == column){ QString taskName = v.toString(); painter->drawText(option.rect, Qt::AlignCenter,taskName); } else if(4== column){ QString taskType = v.toString(); painter->drawText(option.rect, Qt::AlignCenter,taskType); } else if(5 == column){ QString tubeType = v.toString(); painter->drawText(option.rect, Qt::AlignCenter,tubeType); } else if(6 == column){ int tubeNumber = v.toInt(); painter->drawText(option.rect, Qt::AlignCenter, QString::number(tubeNumber)); } else if(7 == column){ int rackNumber = v.toUInt(); painter->drawText(option.rect, Qt::AlignCenter, QString::number(rackNumber)); } else if(8== column){ int beginTime = v.toInt(); QRect timeRect = QRect(option.rect.left(),option.rect.top(),option.rect.width(),option.rect.height()/2); QRect dateRect = QRect(option.rect.left(),option.rect.top()+(option.rect.height()/2),option.rect.width(),option.rect.height()/2); painter->drawText(timeRect,Qt::AlignCenter,QDateTime::fromSecsSinceEpoch(beginTime).toString("hh:mm:ss")); painter->drawText(dateRect,Qt::AlignCenter,QDateTime::fromSecsSinceEpoch(beginTime).toString("yyyy-MM-dd")); } else if(9 == column){// 绘制进度条 int processed = v.toInt(); QStyleOptionProgressBar *processBar = new QStyleOptionProgressBar(); processBar->rect = QRect(option.rect.left(),option.rect.top()+(option.rect.height()/3),option.rect.width(),option.rect.height()/3); processBar->minimum = 0; processBar->maximum = 100; processBar->progress = processed; processBar->text = QString::number(processed)+"%"; processBar->textAlignment = Qt::AlignBottom; processBar->textVisible = true; QApplication::style()->drawControl(QStyle::CE_ProgressBar, processBar, painter); // painter->drawText(option.rect, Qt::AlignCenter, QString::number(processed)); } else if(10 == column){ QString taskOwner = v.toString(); painter->drawText(option.rect, Qt::AlignCenter,taskOwner); } else if(11 == column){ // 绘制选项框 bool checked = v.toBool(); QStyleOptionButton checkButton; checkButton.state |= QStyle::State_Enabled; checkButton.state |= checked ? QStyle::State_On : QStyle::State_Off;// 根据模型值设定是否选中 checkButton.rect = checkBoxRect(option); QApplication::style()->drawControl(QStyle::CE_CheckBox, &checkButton, painter); } painter->restore(); } } QSize myItemDelegate::sizeHint(const QStyleOptionViewItem &option, const QModelIndex &index) const{ qDebug()<< option.rect.width()<< option.rect.height(); //return QSize(option.rect.size()); //return QSize(40,60); return QSize(option.rect.width(), 200); } QRect myItemDelegate::checkBoxRect(const QStyleOptionViewItem &viewItemStyleOptions) const { QStyleOptionButton checkBoxStyleOption; QRect checkBoxRect = QApplication::style()->subElementRect(QStyle::SE_CheckBoxIndicator, &checkBoxStyleOption); QPoint checkBoxPoint(viewItemStyleOptions.rect.x() + (viewItemStyleOptions.rect.width()- checkBoxRect.width())/2, viewItemStyleOptions.rect.y() + (viewItemStyleOptions.rect.height()- checkBoxRect.height())/2); return QRect(checkBoxPoint, checkBoxRect.size()); } bool myItemDelegate::editorEvent(QEvent *event, QAbstractItemModel *model, const QStyleOptionViewItem &option, const QModelIndex &index) { if(index.column() == 11){ if(event->type() == QEvent::MouseButtonRelease){ QMouseEvent *mouseEvent = (QMouseEvent*)event; if(mouseEvent->button() == Qt::LeftButton && checkBoxRect(option).contains(mouseEvent->pos())){ bool checked = index.data(Qt::UserRole + 1 + 11).toBool(); return model->setData(index, !checked, Qt::UserRole + 1 + 11);// 单击选中框设置相反的选中状态 } } } return QStyledItemDelegate::editorEvent(event, model, option, index); //其余事件调用默认实现 }
-测试
.../
QSortFilterProxyModel *sortModel = new QSortFilterProxyModel(); myTableModel *model = new myTableModel(); myItemDelegate *itemDelegate = new myItemDelegate(); ui->tableView->setItemDelegate(itemDelegate); sortModel->setSourceModel(model); sortModel->setDynamicSortFilter(true); sortModel->setSortRole(Qt::UserRole+1); //按照权限排序 ui->tableView->setSortingEnabled(true); ui->tableView->setModel(sortModel); ui->tableView->setSelectionBehavior(QAbstractItemView::SelectRows); ui->tableView->setSelectionMode ( QAbstractItemView::SingleSelection); // ui->tableView->setEditTriggers(QAbstractItemView::NoEditTriggers); ui->tableView->setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff); ui->tableView->horizontalHeader()->setSectionResizeMode(QHeaderView::Stretch); ui->tableView->resizeColumnsToContents(); ui->tableView->setShowGrid(false); for(int i = 0 ;i < 10 ; ++i){ Data d; d.priority = static_cast<Priority>(i); d.taskState = static_cast<State>(9-i); d.taskCode = QString("taskCode%1").arg(i); d.taskName = QString("taskName%1").arg(i); d.taskType = QString("taskType%1").arg(i); d.tubeType = QString("tubeType%1").arg(i); d.tubeNumber = i+100; d.rackNumber = i+10; d.beginTime = QDateTime::currentDateTime().toTime_t(); d.processed = 50+i; d.taskOwner = QString("owner%1").arg(i); model->addData(d); }
/...