c++ 当QDialog中有三个QListView时,QListView刷新缓慢

ukdjmx9f  于 2024-01-09  发布在  其他
关注(0)|答案(1)|浏览(155)

我自定义了从QStringListModel继承的数据模型AnnotationListModel
AnnotationListModel类的目的,是为数据项添加复选框,实现数据项之间的互斥。
现在,我在QDialog中创建了三个QListView和AnnotationListModel对象。模型中的数据项作为复选框添加,并且是独占的。
我可以在QListView中选中复选框,但选中的状态无法快速显示。
如何使QListView快速刷新?

  1. class AnnotationListModel :public QStringListModel
  2. {
  3. Q_OBJECT
  4. public:
  5. AnnotationListModel(AnnotationType annType, const QStringList& stringList, QObject* parent = nullptr);
  6. ~AnnotationListModel() {};
  7. protected:
  8. Qt::ItemFlags flags(const QModelIndex& index) const override;
  9. QVariant data(const QModelIndex& index, int role = Qt::DisplayRole) const override;
  10. bool setData(const QModelIndex& index, const QVariant& value, int role = Qt::EditRole) override;
  11. signals:
  12. void sendAnnotation(const AnnotationType& annoType, const QString& annotation);
  13. private:
  14. AnnotationType m_annoType;
  15. QStringList m_stringList;
  16. QMap<QString, bool> m_stringList_map; //<annotationName,checked>
  17. };
  18. AnnotationListModel::AnnotationListModel(AnnotationType annType, const QStringList& stringList, QObject* parent)
  19. :QStringListModel(parent), m_stringList(stringList), m_annoType(annType)
  20. {
  21. setStringList(m_stringList);
  22. for (auto& value : m_stringList)
  23. {
  24. m_stringList_map[value] = false;
  25. }
  26. }
  27. Qt::ItemFlags AnnotationListModel::flags(const QModelIndex& index) const
  28. {
  29. if (!index.isValid())
  30. {
  31. return Qt::ItemIsEnabled;
  32. }
  33. return Qt::ItemIsUserCheckable | QStringListModel::flags(index);
  34. }
  35. QVariant AnnotationListModel::data(const QModelIndex& index, int role) const
  36. {
  37. if (!index.isValid())
  38. {
  39. return QVariant();
  40. }
  41. if (role == Qt::CheckStateRole)
  42. {
  43. if (m_stringList_map[m_stringList.at(index.row())] == true)
  44. {
  45. return Qt::Checked;
  46. }
  47. else
  48. {
  49. return Qt::Unchecked;
  50. }
  51. }
  52. else if (role == Qt::DisplayRole)
  53. {
  54. return m_stringList.at(index.row());
  55. }
  56. return QStringListModel::data(index, role);
  57. }
  58. bool AnnotationListModel::setData(const QModelIndex& index, const QVariant& value, int role)
  59. {
  60. if (!index.isValid())
  61. {
  62. return false;
  63. }
  64. if (role == Qt::CheckStateRole)
  65. {
  66. if (value == Qt::Checked)
  67. {
  68. for (int i{ 0 }; i < m_stringList.size(); ++i)
  69. {
  70. if (i != index.row())
  71. {
  72. m_stringList_map[m_stringList.at(i)] = false;
  73. }
  74. else
  75. {
  76. m_stringList_map[m_stringList.at(i)] = true;
  77. sendAnnotation(m_annoType, m_stringList.at(i));
  78. }
  79. }
  80. }
  81. else if (value == Qt::Unchecked)
  82. {
  83. m_stringList_map[m_stringList.at(index.row())] = false;
  84. }
  85. }
  86. return QStringListModel::setData(index, value, role);
  87. }

字符串
创建三个AnnotationListModel对象:

  1. switch (itr_kind.key())
  2. {
  3. case AnnotationType::CounCode:
  4. m_counCodeModel = new AnnotationListModel(AnnotationType::CounCode, l_annoStrList);
  5. m_uiDialog->listView_country->setModel(m_counCodeModel);
  6. connect(m_counCodeModel, &AnnotationListModel::sendAnnotation, this, &AnnotationDialog::sendAnnotation);
  7. break;
  8. case AnnotationType::DriSide:
  9. m_driSideModel = new AnnotationListModel(AnnotationType::DriSide, l_annoStrList);
  10. m_uiDialog->listView_driving->setModel(m_driSideModel);
  11. connect(m_driSideModel, &AnnotationListModel::sendAnnotation, this, &AnnotationDialog::sendAnnotation);
  12. break;
  13. case AnnotationType::RoadType:
  14. m_roadTypeModel = new AnnotationListModel(AnnotationType::RoadType, l_annoStrList);
  15. m_uiDialog->listView_road->setModel(m_roadTypeModel);
  16. connect(m_roadTypeModel, &AnnotationListModel::sendAnnotation, this, &AnnotationDialog::sendAnnotation);
  17. }


对话框通过mainwindow打开。


的数据

niknxzdl

niknxzdl1#

在我看来,你犯了四个错误,但最重要的是前两个:

  • 将功能添加到现有模型(在您的情况下为QStringListModel)的正确方法是使用代理模型(QAbstractProxyModel的子类)。它工作得很好,但更容易实现,并且更灵活,因为它可以与任何模型类型一起使用。
  • 当你想让你的复选框是独占的时,你只需要记住选中的那个复选框,而不需要有一个完整的QMap<...>容器。

我相信这就是代码中大部分计算时间被浪费的地方,特别是在调试模式下测试对话框时(容器有很多很多只在调试中完成的检查,这使得它们的使用速度比发布时慢得多)。
至少,不将检查过的索引保存为QModelIndex是正确的。

  • 您忘记从setData方法发出dataChanged信号。
  • 您忘记从setData方法返回false/true。准确地说,确实返回了一个布尔值,但仅由QStringListModel::setData(...)返回,这不是您想要做的。

下面的AnnotationProxyModel为你想要实现的任何模型实现了排他性的复选框。它派生QIdentityProxyModel,并通过QPersistentModelIndex记住选中的索引(与QModelIndex不同,它可以保存)。
我让你检查你是否真的需要保持Q_OBJECT宏和你的信号(S)在下面的定义,如果是的,添加他们回来自己。

  1. #include <QtCore/QIdentityProxyModel>
  2. class AnnotationProxyModel : public QIdentityProxyModel {
  3. public:
  4. AnnotationProxyModel(QObject* parent = nullptr);
  5. QVariant data(const QModelIndex& index, int role) const override;
  6. Qt::ItemFlags flags(const QModelIndex& index) const override;
  7. bool setData(const QModelIndex& index, const QVariant& value, int role) override;
  8. private:
  9. QPersistentModelIndex checkedIndex;
  10. };
  11. AnnotationProxyModel::AnnotationProxyModel(QObject* parent) :
  12. QIdentityProxyModel(parent),
  13. checkedIndex()
  14. {
  15. }
  16. QVariant AnnotationProxyModel::data(const QModelIndex& index, int role) const
  17. {
  18. switch (role) {
  19. case Qt::CheckStateRole: return QVariant((checkedIndex == index) ? Qt::Checked : Qt::Unchecked);
  20. default: return QIdentityProxyModel::data(index, role);
  21. }
  22. }
  23. Qt::ItemFlags AnnotationProxyModel::flags(const QModelIndex& index) const
  24. {
  25. return QIdentityProxyModel::flags(index) | Qt::ItemIsUserCheckable;
  26. }
  27. bool AnnotationProxyModel::setData(const QModelIndex& index, const QVariant& value, int role)
  28. {
  29. switch (role) {
  30. case Qt::CheckStateRole: {
  31. if (checkedIndex == index) {
  32. if (value.value<Qt::CheckState>() != Qt::Unchecked) // Trying to check the already checked index -> return false
  33. return false;
  34. else {
  35. checkedIndex = QPersistentModelIndex(); // Unchecking the already checked index -> return true;
  36. emit dataChanged(index, index, { Qt::CheckStateRole });
  37. return true;
  38. }
  39. }
  40. else {
  41. if (value.value<Qt::CheckState>() == Qt::Unchecked) // Trying to uncheck an index that is already unchecked -> return false
  42. return false;
  43. else {
  44. QModelIndex uncheckedIndex = checkedIndex;
  45. checkedIndex = QPersistentModelIndex(index);
  46. emit dataChanged(uncheckedIndex, uncheckedIndex, { Qt::CheckStateRole });
  47. emit dataChanged(index, index, { Qt::CheckStateRole });
  48. return true;
  49. }
  50. }
  51. }
  52. default: return QIdentityProxyModel::setData(index, value, role);
  53. }
  54. }

字符串
与任何其他代理模型一样,它是通过使用QStringListModel调用setSourceModel(...)来使用的,即以这种方式:

  1. AnnotationProxyModel* checkModel = new AnnotationProxyModel(view);
  2. checkModel->setSourceModel(countryModel);
  3. view->setModel(checkModel);

展开查看全部

相关问题