#ifndef TABLEVIEWEX_H #define TABLEVIEWEX_H #include #include #include #include class TableViewEx : public QTableView { Q_OBJECT public: explicit TableViewEx(QWidget *parent = nullptr); template void Load(const QList &dataList, bool selectFirstRow = true, bool appendMode = false); template void AppendRow(const T &outData, bool setSelected = false); template void InsertRow(const T &data, int nRow); template void RefreshOneRow(const T &data); template bool GetSelected(T &outData); template void SetSelected(const T &data, bool selectFirstIfNotFound = true, bool scrollto = true); template int FindData(T &outData, int id, bool forSourceModel = false); template bool FindData(T &outData, const QModelIndex &index, bool forSourceModel = false); template bool GetData(QList &outList, bool forSourceModel = false); void ClearModel(); bool RemoveRow(int row); bool RemoveRow(const QModelIndex &index); bool IsEmpty(bool forSourceModel = false); void SetCurrentRow(int row); //自定义横纵滚动条 void SetVerticalScrollBar(bool bIsNeed); void SetHorizontalScrollBar(bool bIsNeed); private slots: void OnScrollBarDataChanged(const QModelIndex &topLeft, const QModelIndex &bottomRight, const QVector &roles = QVector()); void OnModelReset(); protected: QAbstractItemModel *GetModel(bool sourceModel); virtual QList Data2RowItems(const QVariant &data, int row) = 0; virtual int GetDataID(const QVariant &data) = 0; virtual void SetHeaders() = 0; virtual void OnLoaded(){} protected: QStandardItemModel m_model; QScrollBar *m_verticalScrollBar{nullptr}; QScrollBar *m_horizontalScrollBar{nullptr}; }; /*---------------------------------------------------------------- * 因为使用了模板, 模板的实例化在cpp文件中, 其他类要调用模板函数时, 要找到实例化的函数, 所以这里必须写在头文件里 ----------------------------------------------------------------*/ template void TableViewEx::Load(const QList &dataList, bool selectFirstRow, bool appendMode) { if(!appendMode) m_model.clear(); for(const T &data: dataList) { QVariant d_T; d_T.setValue(data); //如果Data2RowItems失败, 这里直接return, 否则下面setdata会越界 QList rowItems = Data2RowItems(d_T, m_model.rowCount()); if(rowItems.isEmpty()) return; m_model.appendRow(rowItems); QModelIndex index = m_model.index(m_model.rowCount()-1, 0); m_model.setData(index, d_T, Qt::UserRole); } SetHeaders(); //加载完成后选中第一个 if(selectFirstRow && !dataList.isEmpty()) SetCurrentRow(0); OnLoaded(); } template void TableViewEx::AppendRow(const T &data, bool setSelected) { QVariant d_T; d_T.setValue(data); //如果Data2RowItems失败, 这里直接return, 否则下面setdata会越界 QList rowItems = Data2RowItems(d_T, m_model.rowCount()); if(rowItems.isEmpty()) return; m_model.appendRow(rowItems); QModelIndex index = m_model.index(m_model.rowCount()-1, 0); m_model.setData(index, d_T, Qt::UserRole); SetHeaders(); if(setSelected) SetSelected(data); } template void TableViewEx::InsertRow(const T &data, int nRow) { QVariant d_T; d_T.setValue(data); //如果Data2RowItems失败, 这里直接return, 否则下面setdata会越界 QList rowItems = Data2RowItems(d_T, m_model.rowCount()); if(rowItems.isEmpty()) return; m_model.insertRow(nRow, rowItems); QModelIndex index = m_model.index(nRow, 0); m_model.setData(index, d_T, Qt::UserRole); SetHeaders(); } template void TableViewEx::RefreshOneRow(const T &data) { QVariant d_data; d_data.setValue(data); T t; int row = FindData(t, GetDataID(d_data), true); if(row == -1) return; //修改表格里的文本 QList rowItems = Data2RowItems(d_data, row); for(QStandardItem *pItem: rowItems) { m_model.item(row, rowItems.indexOf(pItem))->setText(pItem->text()); } qDeleteAll(rowItems); //修改存在model第一列的data QModelIndex index = m_model.index(row, 0); m_model.setData(index, d_data, Qt::UserRole); } template bool TableViewEx::GetSelected(T &outData) { //如果使用了代理model, 则该函数失效, 因为currentIndex().row()返回的是代理model的当前行 //if((&m_model) != model()) //{ // qDebug()<<"使用了代理model, GetSelected失败"; // return false; //} if(currentIndex().row() == -1) return false; QVariant modelData = model()->data(model()->index(currentIndex().row(), 0), Qt::UserRole); if(!modelData.isValid()) return false; if(!modelData.canConvert()) return false; outData = modelData.value(); return true; } template void TableViewEx::SetSelected(const T &data, bool selectFirstIfNotFound, bool scrollto) { if(m_model.rowCount() == 0) return; QVariant d_data; d_data.setValue(data); //先取消选中, 再选中回原来那行 selectionModel()->clear(); //这里直接按正在使用的model来FindData, 不管table是否使用了代理model, 返回的row传给SetCurrentRow都合理 T t; int row = FindData(t, GetDataID(d_data), false); if(row == -1) { if(selectFirstIfNotFound) SetCurrentRow(0); } else { SetCurrentRow(row); } if(scrollto) scrollTo(currentIndex()); } template int TableViewEx::FindData(T &outData, int id, bool forSourceModel) { QAbstractItemModel *pModel = GetModel(forSourceModel); for (int row = 0; row < pModel->rowCount(); ++row) { QVariant modelData = pModel->data(pModel->index(row, 0), Qt::UserRole); if(!modelData.isValid()) continue; if(GetDataID(modelData) != id) continue; if(!modelData.canConvert()) continue; outData = modelData.value(); return row; } return -1; } template bool TableViewEx::FindData(T &outData, const QModelIndex &index, bool forSourceModel) { QAbstractItemModel *pModel = GetModel(forSourceModel); QModelIndex rowIndex = pModel->index(index.row(), 0); if(!pModel->data(rowIndex, Qt::UserRole).canConvert()) return false; outData = pModel->data(rowIndex, Qt::UserRole).value(); return true; } template bool TableViewEx::GetData(QList &outList, bool forSourceModel) { QAbstractItemModel *pModel = GetModel(forSourceModel); outList.clear(); for (int row = 0; row < pModel->rowCount(); ++row) { QVariant modelData = pModel->data(pModel->index(row, 0), Qt::UserRole); if(!modelData.isValid()) return false; if(!modelData.canConvert()) return false; outList.append(modelData.value()); } return true; } #endif // TABLEVIEWEX_H