tableviewex.h 7.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223
  1. #ifndef TABLEVIEWEX_H
  2. #define TABLEVIEWEX_H
  3. #include <QWidget>
  4. #include <QTableView>
  5. #include <QStandardItemModel>
  6. #include <QDebug>
  7. class TableViewEx : public QTableView
  8. {
  9. Q_OBJECT
  10. public:
  11. explicit TableViewEx(QWidget *parent = nullptr);
  12. template<typename T> void Load(const QList<T> &dataList, bool selectFirstRow = true, bool appendMode = false);
  13. template<typename T> void AppendRow(const T &outData, bool setSelected = false);
  14. template<typename T> void InsertRow(const T &data, int nRow);
  15. template<typename T> void RefreshOneRow(const T &data);
  16. template<typename T> bool GetSelected(T &outData);
  17. template<typename T> void SetSelected(const T &data, bool selectFirstIfNotFound = true, bool scrollto = true);
  18. template<typename T> int FindData(T &outData, int id, bool forSourceModel = false);
  19. template<typename T> bool FindData(T &outData, const QModelIndex &index, bool forSourceModel = false);
  20. template<typename T> bool GetData(QList<T> &outList, bool forSourceModel = false);
  21. void ClearModel();
  22. bool RemoveRow(int row);
  23. bool RemoveRow(const QModelIndex &index);
  24. bool IsEmpty(bool forSourceModel = false);
  25. void SetCurrentRow(int row);
  26. //自定义横纵滚动条
  27. void SetVerticalScrollBar(bool bIsNeed);
  28. void SetHorizontalScrollBar(bool bIsNeed);
  29. private slots:
  30. void OnScrollBarDataChanged(const QModelIndex &topLeft, const QModelIndex &bottomRight, const QVector<int> &roles = QVector<int>());
  31. void OnModelReset();
  32. protected:
  33. QAbstractItemModel *GetModel(bool sourceModel);
  34. virtual QList<QStandardItem*> Data2RowItems(const QVariant &data, int row) = 0;
  35. virtual int GetDataID(const QVariant &data) = 0;
  36. virtual void SetHeaders() = 0;
  37. virtual void OnLoaded(){}
  38. protected:
  39. QStandardItemModel m_model;
  40. QScrollBar *m_verticalScrollBar{nullptr};
  41. QScrollBar *m_horizontalScrollBar{nullptr};
  42. };
  43. /*----------------------------------------------------------------
  44. * 因为使用了模板, 模板的实例化在cpp文件中, 其他类要调用模板函数时, 要找到实例化的函数, 所以这里必须写在头文件里
  45. ----------------------------------------------------------------*/
  46. template<typename T>
  47. void TableViewEx::Load(const QList<T> &dataList, bool selectFirstRow, bool appendMode)
  48. {
  49. if(!appendMode) m_model.clear();
  50. for(const T &data: dataList)
  51. {
  52. QVariant d_T;
  53. d_T.setValue(data);
  54. //如果Data2RowItems失败, 这里直接return, 否则下面setdata会越界
  55. QList<QStandardItem*> rowItems = Data2RowItems(d_T, m_model.rowCount());
  56. if(rowItems.isEmpty()) return;
  57. m_model.appendRow(rowItems);
  58. QModelIndex index = m_model.index(m_model.rowCount()-1, 0);
  59. m_model.setData(index, d_T, Qt::UserRole);
  60. }
  61. SetHeaders();
  62. //加载完成后选中第一个
  63. if(selectFirstRow && !dataList.isEmpty()) SetCurrentRow(0);
  64. OnLoaded();
  65. }
  66. template<typename T>
  67. void TableViewEx::AppendRow(const T &data, bool setSelected)
  68. {
  69. QVariant d_T;
  70. d_T.setValue(data);
  71. //如果Data2RowItems失败, 这里直接return, 否则下面setdata会越界
  72. QList<QStandardItem*> rowItems = Data2RowItems(d_T, m_model.rowCount());
  73. if(rowItems.isEmpty()) return;
  74. m_model.appendRow(rowItems);
  75. QModelIndex index = m_model.index(m_model.rowCount()-1, 0);
  76. m_model.setData(index, d_T, Qt::UserRole);
  77. SetHeaders();
  78. if(setSelected) SetSelected(data);
  79. }
  80. template<typename T>
  81. void TableViewEx::InsertRow(const T &data, int nRow)
  82. {
  83. QVariant d_T;
  84. d_T.setValue(data);
  85. //如果Data2RowItems失败, 这里直接return, 否则下面setdata会越界
  86. QList<QStandardItem*> rowItems = Data2RowItems(d_T, m_model.rowCount());
  87. if(rowItems.isEmpty()) return;
  88. m_model.insertRow(nRow, rowItems);
  89. QModelIndex index = m_model.index(nRow, 0);
  90. m_model.setData(index, d_T, Qt::UserRole);
  91. SetHeaders();
  92. }
  93. template<typename T>
  94. void TableViewEx::RefreshOneRow(const T &data)
  95. {
  96. QVariant d_data;
  97. d_data.setValue(data);
  98. T t;
  99. int row = FindData(t, GetDataID(d_data), true);
  100. if(row == -1) return;
  101. //修改表格里的文本
  102. QList<QStandardItem*> rowItems = Data2RowItems(d_data, row);
  103. for(QStandardItem *pItem: rowItems)
  104. {
  105. m_model.item(row, rowItems.indexOf(pItem))->setText(pItem->text());
  106. }
  107. qDeleteAll(rowItems);
  108. //修改存在model第一列的data
  109. QModelIndex index = m_model.index(row, 0);
  110. m_model.setData(index, d_data, Qt::UserRole);
  111. }
  112. template<typename T>
  113. bool TableViewEx::GetSelected(T &outData)
  114. {
  115. //如果使用了代理model, 则该函数失效, 因为currentIndex().row()返回的是代理model的当前行
  116. //if((&m_model) != model())
  117. //{
  118. // qDebug()<<"使用了代理model, GetSelected失败";
  119. // return false;
  120. //}
  121. if(currentIndex().row() == -1) return false;
  122. QVariant modelData = model()->data(model()->index(currentIndex().row(), 0), Qt::UserRole);
  123. if(!modelData.isValid()) return false;
  124. if(!modelData.canConvert<T>()) return false;
  125. outData = modelData.value<T>();
  126. return true;
  127. }
  128. template<typename T>
  129. void TableViewEx::SetSelected(const T &data, bool selectFirstIfNotFound, bool scrollto)
  130. {
  131. if(m_model.rowCount() == 0) return;
  132. QVariant d_data;
  133. d_data.setValue(data);
  134. //先取消选中, 再选中回原来那行
  135. selectionModel()->clear();
  136. //这里直接按正在使用的model来FindData, 不管table是否使用了代理model, 返回的row传给SetCurrentRow都合理
  137. T t;
  138. int row = FindData(t, GetDataID(d_data), false);
  139. if(row == -1)
  140. {
  141. if(selectFirstIfNotFound) SetCurrentRow(0);
  142. }
  143. else
  144. {
  145. SetCurrentRow(row);
  146. }
  147. if(scrollto) scrollTo(currentIndex());
  148. }
  149. template<typename T>
  150. int TableViewEx::FindData(T &outData, int id, bool forSourceModel)
  151. {
  152. QAbstractItemModel *pModel = GetModel(forSourceModel);
  153. for (int row = 0; row < pModel->rowCount(); ++row)
  154. {
  155. QVariant modelData = pModel->data(pModel->index(row, 0), Qt::UserRole);
  156. if(!modelData.isValid()) continue;
  157. if(GetDataID(modelData) != id) continue;
  158. if(!modelData.canConvert<T>()) continue;
  159. outData = modelData.value<T>();
  160. return row;
  161. }
  162. return -1;
  163. }
  164. template<typename T>
  165. bool TableViewEx::FindData(T &outData, const QModelIndex &index, bool forSourceModel)
  166. {
  167. QAbstractItemModel *pModel = GetModel(forSourceModel);
  168. QModelIndex rowIndex = pModel->index(index.row(), 0);
  169. if(!pModel->data(rowIndex, Qt::UserRole).canConvert<T>()) return false;
  170. outData = pModel->data(rowIndex, Qt::UserRole).value<T>();
  171. return true;
  172. }
  173. template<typename T>
  174. bool TableViewEx::GetData(QList<T> &outList, bool forSourceModel)
  175. {
  176. QAbstractItemModel *pModel = GetModel(forSourceModel);
  177. outList.clear();
  178. for (int row = 0; row < pModel->rowCount(); ++row)
  179. {
  180. QVariant modelData = pModel->data(pModel->index(row, 0), Qt::UserRole);
  181. if(!modelData.isValid()) return false;
  182. if(!modelData.canConvert<T>()) return false;
  183. outList.append(modelData.value<T>());
  184. }
  185. return true;
  186. }
  187. #endif // TABLEVIEWEX_H